何时初始化实例变量并分配值?

AKh*_*AKh 9 java inheritance abstract-class object instance

当doees实例变量初始化时?是在构造函数块完成之后还是之前?

考虑这个例子:

public abstract class Parent {

 public Parent(){
   System.out.println("Parent Constructor");
   init();
 }

 public void init(){
   System.out.println("parent Init()");
 }
}
Run Code Online (Sandbox Code Playgroud)
public class Child extends Parent {

private Integer attribute1;
private Integer attribute2 = null;

public Child(){
    super();
    System.out.println("Child Constructor");
}

public void init(){
    System.out.println("Child init()");
    super.init();
    attribute1 = new Integer(100);
    attribute2 = new Integer(200);
}

public void print(){
    System.out.println("attribute 1 : " +attribute1);
    System.out.println("attribute 2 : " +attribute2);
}
}
Run Code Online (Sandbox Code Playgroud)
public class Tester {

public static void main(String[] args) {
    Parent c = new Child();
    ((Child)c).print();

}
}
Run Code Online (Sandbox Code Playgroud)

OUTPUT:

父构造函数

子init()

父Init()

儿童构造函数

属性1:100

属性2:null


  1. 当在堆中分配属性1和2的内存时?

  2. 很想知道为什么属性2是NULL?

  3. 有任何设计缺陷吗?

Mik*_*uel 11

当在堆中分配属性1和2的内存时?

new调用运算符之前,在输入java.lang.Object构造函数之前,将分配整个对象的内存.内存是为各个Integer实例分配的init,但是没有必要为各个属性分配内存 - 只有整个对象.

很想知道为什么属性2是NULL?

init方法在超级构造函数中调用,因此attribute2被赋值new Integer(200),然后调用子类构造函数,它按照它们在源代码中出现的顺序应用属性初始值设定项.这条线

private Integer attribute2 = null;
Run Code Online (Sandbox Code Playgroud)

覆盖由init()to 分配的值null.

如果你添加一个电话

 System.out.println("attribute 2 : " +attribute2);
Run Code Online (Sandbox Code Playgroud)

在你打电话super();之后,这将变得明显.

有任何设计缺陷吗?

在基类完成初始化之前调用子类方法是危险的.子类可能依赖于它的基类的不变量来保护它自己的不变量,如果基类构造函数没有完成,那么它的不变量可能不成立.

这也可能会混淆C++程序员之类的人,他们希望init从基类调用来调用基类的版本,因为C++会在输入构造函数时重写vtable指针.

有关所有血腥细节,请参阅Java语言规范.