5
class A {int x = 5;}
class B extends A {int x = 10;}
class D {
    public static void main(String[] args){
        A b0 = new B();
        System.out.print(b0.x);
    }
}

I am wondering why this code prints 5 instead of 10.

If I instead write the following, converting the variables x to methods, it works more as I'd expect, and prints out 10, since at compile time it merely checked if b0's static type, A, has a method x, and then at runtime, uses b0's dynamic type, B, to run x.

class A {int x() {return 5;}}
class B extends A {int x() {return 10;}}
class D {
    public static void main(String[] args){
        A b0 = new B();
        System.out.print(b0.x());
    }
}

My theory is that instance variables are looked up statically unlike methods, but I am not sure about why that would be.

Thanks!

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
FLOWMEEN
  • 375
  • 1
  • 3
  • 11

3 Answers3

4

In B the field x from A is shadowed(hidden) not overriden. To answer "why that would be" references to the docs here and here. The compiler will pick one of the 2 instances of x according to the type of the containing object. And b0 is of type A

 A b0 = new B();

When you define (getter) methods on the other hand these can override methods with the same signature in the parent class. Another nasty surprise is that a field in the parent class is shadowed even if it's a different type.

Shadowing of members is considered a bad practice as it tends to confuse developers.

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
4

Because you are accessing the variable x from the class A, since b0 is defined as A. It is called hiding a variable, and not as you might suspect overriding a variable, which is not possible in java. You would get your expected result if you would access x from b0 by using a typeCast.

A b0 = new B();
System.out.print(((B)b0).x);

By using a typeCast you would be accessing the variable x from the class B now.

for further information you could read through JLS 8.3

SomeJavaGuy
  • 7,307
  • 2
  • 21
  • 33
3

Static fields are not inherited, they do not override each other, they shadow each other. When you directly access Static field of the same name in your case, the field of superclass hides the other field and you have two int Xes but the one of the superclass is not hidden and gets picked. Even better yet, when you call another instance of the same method and access the same static field, that is when things get very weird. The static fields get added together and you may end up with X being 5+5 = 10.

On the other hand, if you inherit non static field from superclass, there is no problem of it having different value in sub-class, because the sub-class can override the non-static super member.

Static variables and inheritance is bad, it breaks the polymorphism where you would least expect it. (Actually, if you understand concepts of your language, you expect it, but other people may not)

The Law
  • 344
  • 3
  • 20