简体   繁体   中英

Initializing an instance variable in both parent and child

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"

Live Example

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM