I have the following Java code
public class Base {
private static boolean goo = true;
protected static boolean foo() {
goo = !goo;
return goo;
}
public String bar = "Base:" + foo();
public static void main(String[] args) {
Base base = new Sub();
System.out.println(base.bar);
}
}
public class Sub extends Base {
public String bar = "Sub:" + foo();
}
And I'm asked what it would print. After testing this the answer seems to be Base:false
, but I'm really unable to understand why is it not Sub:true
.
Running through the debugger with a Breakpoint on the final print I have the following object:
which shows base having two variables with the same name! one having the printed Base:false and the other the expected (by me) Sub:true. Indeed foo() is called twice but each time instantiating a different variable? Shouldn't the variable with the same name created in the subclass (and initialized after the first one is created) override the one in the parent class? How does Java choose which one to print?
...which shows base having two variables with the same name!
Yup! base
is a reference to a Sub
instance, and that Sub
instance has two bar
fields. Let's call them Base$bar
and Sub$bar
:
+------------------------+ base--->| Sub instance | +------------------------+ | Base$bar: "Base:false" | | Sub$bar: "Sub:true" | +------------------------+
Java allows for the same name being used at different levels in an instance's type hierarchy. (It has to: Frequently these are private fields, and so a subclass may not even know that the superclass has one with the same name.)
Those two different fields in the instance have different values: Base$bar
has the value Base:false
because it's initialized based on the first-ever call to foo
, which flips goo
(which starts as true
) and uses the flipped result. Sub$bar
has the value Sub:true
because it's initialized from the second-ever call to foo
, so goo
is flipped again and the updated value is used. There is only one instance created, but foo
is called twice.
Which bar
you see when you access bar
depends on the type of the reference you have to the instance. Because base
is declared of type Base
, when you do base.bar
you access the Base$bar
field in the Sub
instance. If you had a Sub
reference to the instance, you'd access Sub$bar
instead:
System.out.println(base.bar); // "Base:false"
System.out.println(((Sub)base).bar); // "Sub:true"
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.