65

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?

Alessandro Da Rugna
  • 4,571
  • 20
  • 40
  • 64
  • 3
    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 Sep 06 '15 at 19:48
  • Related: http://stackoverflow.com/questions/13748124/why-java-polymorphism-not-work-in-my-example – user11153 Sep 07 '15 at 06:46

4 Answers4

46

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.

Community
  • 1
  • 1
M A
  • 71,713
  • 13
  • 134
  • 174
25

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;
    }
}
Clashsoft
  • 11,553
  • 5
  • 40
  • 79
  • 4
    Much better than my answer would have been: Because the language was designed that way. – Andreas Sep 06 '15 at 11:22
  • 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 Sep 06 '15 at 11:50
  • 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 Sep 06 '15 at 15:11
  • Unless I misunderstand your definition of "dynamic variable resolution", I can think of many languages that have it - dynamic languages such as Python or JavaScript typically resolve variables at runtime, and even Scala (a static language) looks up variables polymorphically. – James_pic Sep 07 '15 at 09:36
  • I edited to include statically typed languages only. Scala depends on the JVM and sort of 'cheats' this by generating accessor method for fields. I don't know if that override behavior is intended by their compiler developers. – Clashsoft Sep 09 '15 at 15:16
  • The `MyDerivedClass.var` could have a different type, too. In order to make the dynamic access possible, the language designers need to ensure type safety, so there should be a kind of _variable override_ or something like that, like it's done for virtual methods. – Vlad Sep 10 '15 at 21:24
5

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.

alainlompo
  • 4,414
  • 4
  • 32
  • 41
2

In java, this is by design. Because, the set up of fields to be dynamically resolved would make things to run a bit slower. And in real, there's not any reason of doing so. Since, you can make your fields in any class private and access them with methods which are dynamically resolved.

So, fields are made to resolved better at compile time instead :)