我有一个简单的Java程序:
Test2
实例化Test
时,它的构造函数会调用foo
的构造函数,后者会调用Test2
中实现的方法foo
在执行testObj
期间,字段null
为{{1}},即使它是最终的。
这是正确的行为吗?如果是这样,是否有解决方案?
答案 0 :(得分:2)
是的,这是正确的行为:派生类的foo()
仅在超类初始化之后才被初始化;由于{<1}}在超级类初始化之前被称为,testObj
仍为null
。
解决此问题的最佳方法是不在构造函数中调用抽象方法,因为它们可能会发现它们的对象处于未初始化状态。另一种方法是将呼叫推迟到foo()
。如果foo
必须作为初始化序列的一部分被调用,因为它为基类提供了某些东西,它不应该访问实例上的任何状态。
答案 1 :(得分:0)
您正在调用Test2
方法,而Test2
尚未完成构建,只有对象的Test
部分已完成。因此,Test2
的实例变量尚未分配(幸运的是它们是null
而不是一些随机内存指针!)
&#39;正确&#39;模式是不在基类中调用抽象方法&#39;构造函数,如果你真的不需要让该方法依赖于它的实例变量,而只依赖于参数。
答案 2 :(得分:0)
即使你没有将super()方法放在基类的构造函数中。编译器将自己放置super()方法。例如:
class A {
A() {
System.out.println("A");
}
}
class B extends A {
B() {
System.out.println("B");
}
}
class C extends B {
C() {
System.out.println("C");
}
public static void main(String[] args) {
C c = new C();
}
}
您可以通过在每个构造函数的第一行放置super()方法来重新检查上述函数。工作流程不会改变。还有另一个规则,即super()和this()方法将始终只放在构造函数的第一行。这是继承情况下java的工作流程。
现在回答你的问题。在创建Test2的实例时,在初始化testobj之前从构造函数中调用super()方法。因此,当从基类Test调用foo()方法时,testobj没有被初始化并调用函数,这就是为什么它显示为null。