在父级和子级中初始化实例变量

Nes*_*cio 4 java

我有以下Java代码

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();
}
Run Code Online (Sandbox Code Playgroud)

而且我被问到它会打印什么.经过测试,答案似乎是Base:false,但我真的无法理解为什么不是Sub:true.

在最终打印中使用断点运行调试器我有以下对象: 调试器基础

它显示了具有两个同名变量的基数!一个有印刷的基础:假,另一个是预期的(由我)Sub:true.实际上foo()被调用两次但每次实例化一个不同的变量?不应该在子类中创建具有相同名称的变量(并在创建第一个之后初始化)覆盖父类中的变量吗?Java如何选择打印哪一个?

T.J*_*der 6

...显示具有两个同名变量的基数!

对!base是对Sub实例的引用,该Sub实例有两个 bar字段.让我们把他们Base$barSub$bar:

        +------------------------+
base--->|      Sub instance      |
        +------------------------+
        | Base$bar: "Base:false" |
        | Sub$bar:  "Sub:true"   |
        +------------------------+

Java允许在实例的类型层次结构中的不同级别使用相同的名称.(它必须:经常这些是私有字段,因此子类甚至可能不知道超类有一个具有相同名称的子类.)

实例中的这两个不同的字段具有不同的值:Base$bar具有该值,Base:false因为它是基于第一次调用而初始化的foo,其翻转goo(以其开始true)并使用翻转的结果.Sub$bar具有该值,Sub:true因为它是从第二次调用初始化的foo,因此goo再次翻转并使用更新的值.只创建了一个实例,但foo调用了两次.

其中bar你看,当你访问bar取决于你有实例的引用的类型.因为base声明了类型Base,所以当base.bar您访问实例中的Base$bar字段时Sub.如果您有Sub对该实例的引用,则可以访问Sub$bar:

System.out.println(base.bar);        // "Base:false"
System.out.println(((Sub)base).bar); // "Sub:true"
Run Code Online (Sandbox Code Playgroud)

实例