Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free.

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?

share|improve this question
    
A side note for a similar language: in C# you'll have compile time binding in all cases, unless you specifically use virtual and override. And you can't use them for variables. –  edc65 12 hours ago
    

3 Answers 3

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 class T, the expression s.x refers to the x field of class S, because the type of the expression s is S. Objects of class T contain two fields named x, one for class T and one for its superclass S.

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 type T 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.

share|improve this answer

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 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;
    }
}
share|improve this answer
2  
Much better than my answer would have been: Because the language was designed that way. –  Andreas 21 hours ago
2  
"You wouldn't be able to access the MyClass.var field at all if you had a MyDerivedClass instance." The same is true for methods, so this isn't really a reason at all. –  Jens Schauder 20 hours ago
1  
@JensSchauder true, but for methods you always know that you override the other method, and that is the most well-known key feature of OO. –  Clashsoft 17 hours ago

The polymorphic behaviour of the java language works with methods and not member variables: they designed the language to bind member variables at compile time.

share|improve this answer
2  
There's no 'therefore' about that second sentence: it's just a restatement of the first sentence. –  EJP 20 hours ago
    
@EJP, thank you. I have edited it –  alainlompo 20 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.