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

时间:2016-07-04 08:13:31

标签: 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();
}

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

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

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

1 个答案:

答案 0 :(得分: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"

Live Example