Consider the following example code
class MyClass { public String var = "base"; public void printVar() { System.out.println(var); } } class MyDerivedClass extends MyClass { public String var = "derived"; public void printVar() { System.out.println(var); } } public class Binding { public static void main(String[] args) { MyClass base = new MyClass(); MyClass derived = new MyDerivedClass(); System.out.println(base.var); System.out.println(derived.var); base.printVar(); derived.printVar(); } }
it gives the following output
base base base derived
Method calls are resolved at runtime and the correct overridden method is called, as expected.
The variables access is instead resolved at compile time as I later learned. I was expecting an output as
base derived base derived
because in the derived class the re-definition of var
shadows the one in the base class.
Why does the binding of variables happens at compile time and not at runtime? Is this only for performance reasons?
Hence compiler doesn't have any difficulty determining the object of the class (local class for sure). That's the reason binding for such methods is static. It takes place at runtime so do it is referred to as late binding. It uses overriding methods.
Polymorphism allows an object to take multiple forms – when a method exhibits polymorphism, the compiler has to map the name of the method to the final implementation. If it's mapped at compile time, it's a static or early binding. If it's resolved at runtime, it's known as dynamic or late binding.
Dynamic binding allows us to ignore the type differences by providing us with the flexibility in choosing which type of function we need at that instant of runtime. On examining this statement, we can understand that dynamic binding allows us to handle different objects using just a single function name.
inheritance is always achieched at compile time. the code acquires reusability with extends keyword even before entering into jvm for verification and thus converting to bytecode,although we can only use its features at run-time after the creation of the object.
Connecting a method call to the method body is known as binding. Static Binding (also known as Early Binding). Dynamic Binding (also known as Late Binding). Let's understand the type of instance. Each variable has a type, it may be primitive and non-primitive. Here data variable is a type of int.
Static vs Dynamic Binding in Java. Static Binding: The binding which can be resolved at compile time by compiler is known as static or early binding. Binding of all the static, private and final methods is done at compile-time .
Connecting a method call to the method body is known as binding. Static Binding (also known as Early Binding). Dynamic Binding (also known as Late Binding). Let's understand the type of instance. Each variable has a type, it may be primitive and non-primitive.
Each variable has a type, it may be primitive and non-primitive. Here data variable is a type of int. An object is an instance of particular java class,but it is also an instance of its superclass. Here d1 is an instance of Dog class, but it is also an instance of Animal.
While you might be right about performance, there is another reason why fields are not dynamically dispatched: You wouldn't be able to access the MyClass.var
field at all if you had a MyDerivedClass
instance.
Generally, I don't know about any statically typed language that actually has dynamic variable resolution. But if you really need it, you can make getters or accessor methods (which should be done in most cases to avoid public
fields, anyway):
class MyClass { private String var = "base"; public String getVar() // or simply 'var()' { return this.var; } } class MyDerivedClass extends MyClass { private String var = "derived"; @Override public String getVar() { return this.var; } }
The reason is explained in the Java Language Specification in an example in Section 15.11, quoted below:
...
The last line shows that, indeed, the field that is accessed does not depend on the run-time class of the referenced object; even if
s
holds a reference to an object of classT
, the expressions.x
refers to thex
field of classS
, because the type of the expressions
isS
. Objects of class T contain two fields namedx
, one for classT
and one for its superclassS
.This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used...
So yes performance is a reason. The specification of how the field access expression is evaluated is stated as follows:
If the field is not
static
:...
- If the field is a non-blank
final
, then the result is the value of the named member field in typeT
found in the object referenced by the value of the Primary.
where Primary in your case refers the variable derived
which is of type MyClass
.
Another reason, as @Clashsoft suggested, is that in subclasses, fields are not overriden, they are hidden. So it makes sense to allow which fields to access based on the declared type or using a cast. This is also true for static methods. This is why the field is determined based on the declared type. Unlike overriding by instance methods where it depends on the actual type. The JLS quote above indeed mentions this reason implicitly:
The power of late binding and overriding is available, but only when instance methods are used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With