成员初始化后?

时间:2014-07-06 10:41:26

标签: java oop inheritance

考虑以下课程:

public class A {
    String bar = "A.bar";

    A() { foo(); }

    public void foo() {
        System.out.println("A.foo(): bar = " +
        bar);
    }
}


public class B extends A {
    String bar = "B.bar";

    B() { foo(); }

    public void foo() {
        System.out.println("B.foo(): bar = " +
        bar);
    }
}

public class C {
    public static void main(String[]
    args) {
        A a = new B();
        System.out.println("a.bar = "
        + a.bar);
        a.foo();
    }
}

现在,打印的第一行是:B.foo(): bar = null。根据我的理解,成员初始化在构造函数之前,但我可以看到这不是这种情况。

为什么此阶段B#bar未初始化?
B#bar何时初始化?

谢谢!

更新
在阅读完答案后,请看一下这个反例:

public class Bazz {

    public int a = 42;

    public Bazz() {
        System.out.println(a);
    }

    public static void main(String[] args) {
        Bazz bazz = new Bazz();
    }
}

在这种情况下,a不是0。相反,Bazz()的构造函数会打印42 有什么不同?

4 个答案:

答案 0 :(得分:3)

让我列举一下步骤:

  • A a = new B(); //看到B是孩子,所以调用A的构造函数(B.bar尚未初始化)
  • 在A的构造函数foo中被调用。因为它被B覆盖所以B的foo被调用并显示为空。
  • A的构造函数完成后B.bar被初始化。
  • 然后调用B的构造函数。

注意:即使未在B中调用super(),编译器也会自动添加此语句。

编辑:编译器如何看待B的构造函数:

  

超级();

     

this.bar =“B.bar”;

     

FOO();

更新:您的新结果来自我之前提供的相同解释:

  • Bazz bazz = new Bazz(); //当调用构造函数时,变量a初始化为42

  • System.out.println(a); //打印42

实例变量在执行构造函数之前初始化,但是在执行super的构造函数之后。请参阅上面的编辑。

答案 1 :(得分:1)

您正在构建new B(),而在构造函数B()中,它会调用super()

因此,您的代码会调用A a = new B();,该代码会落到System.out.println("B.foo(): bar = " + bar);。此时a尚未完成构建(未完全初始化),因此B.barnull。当构造函数在bar处执行步骤返回时,= "B.bar"将使用}进行初始化。

TL; DR:

  

为什么此阶段B#bar未初始化?

因为a未在System.out.println("B.foo(): bar = " + bar);完全初始化。

  

B#bar何时初始化?

}(构造函数结束)。

记录中,这是STDOUT日志:

  

B.foo():bar = null //未初始化bar。我们在:A() { foo(); }

     

B.foo():bar = B.bar // bar已初始化。我们在:B() { foo(); }

     

a.bar = A.bar //你打电话给“println a.bar = a.bar”。在A a中,bar等于a.bar。

     

B.foo():bar = B.bar // foo()是多态的,因为aclass B,所以B.foo()被调用,因此这一行。


@edit: Bazz.a的类型为intint永远不会是null,编译器会自动将这些变量替换为编译器传递的语句。因此System.out.println(a);变为System.out.println(42);

答案 2 :(得分:0)

从类创建对象时,静态初始化程序首先运行。

它初始化静态属性和静态方法,

然后运行对象初始值设定项

首先,它运行对象B()的构造函数,

所以非静态属性(bar)稍后会被初始化。所以属性在执行构造函数后初始化。所以吧是null

如果您将bar声明为静态,

static String bar = "B.bar";

您可以先将条形变量初始化;

输出将是;

B.foo():bar = B.bar

B.foo():bar = B.bar

a.bar = A.bar

B.foo():bar = B.bar

答案 3 :(得分:0)

订单是:

  1. 初始化A.bar
  2. 执行A的构造函数
  3. 初始化B.bar
  4. 执行B的构造函数
  5. 请注意bar中的AbarB的变量不同。因为A的构造函数调用了重写方法,所以此方法可以在B初始化之前访问实例变量。