我正在使用Java 7并获得3个类:
TestSuper.java
public abstract class TestSuper {
public TestSuper() {
testMethod();
}
protected abstract void testMethod();
}
TestNull.java
public class TestNull extends TestSuper {
private String test = "Test";
public TestNull() {
super();
System.out.println(test);
}
@Override
protected void testMethod() {
System.out.println(test);
}
}
TestMain.java
public class TestMain {
public static void main(String[] args) {
new TestNull();
}
}
输出:
null
Test
为什么会发生这种情况并且有一个很好的解决方法呢?
答案 0 :(得分:7)
当您致电new TestNull();
时,您正在调用类TestNull
的构造函数,它调用super()
构造函数:它包含对TestNull
中实现的方法的调用在那里打印字符串字段,此时子类TestNull
的字段尚未初始化,即为空。
在超级构造函数调用之后,将初始化所有字段,因此第二个打印实际上显示(初始化)字符串的新值。
这里的关键点是,在超类的实例化之后,初始化了一个子类的字段。
解决方法?这取决于你想要的确切行为:也许在超级构造函数中调用抽象方法是有意义的(即在TestSuper
类的构造函数中)。
答案 1 :(得分:2)
抽象类的子类本身不是抽象的 实例化,导致执行构造函数 抽象类和,因此,执行 字段初始值设定项 例如该类的变量。
答案 2 :(得分:1)
您正在构造函数中调用可覆盖的实例方法(在您的情况下也调用实例字段private String test = "Test";
)。这可能会导致不一致,因为实例未完全构造。这是一种不好的做法,所以要避免它:
public TestSuper() {
testMethod();
}
请阅读此主题:What's wrong with overridable method calls in constructors?
答案 3 :(得分:0)
您可以通过将testMethod()
的调用移到单独的函数来解决此问题
public abstract class TestSuper {
public TestSuper() { }
public void callTestMethod(){
testMethod();
}
protected abstract void testMethod();
}
然后在callTestMethod()
构造函数上调用TestNull
public TestNull() {
super.callTestMethod();
System.out.println(test);
}