在处理我公司的遗留代码时,我在运行时遇到了NPE。 调试之后,这就是我遇到的情况:
public class ConcreteClass extends PreConcreteClass{
private List<Object> internalDS = new ArrayList<>();
public ConcreteClass() {
super();
....
}
@Override
protected void update() {
....
for(Object o : internalDS) {
...
}
...
}
public class PreConcreteClass extends AbstractClass{
......
public PreConcreteClass() {
super();
......
}
......
}
protected abstract class AbstractClass {
protected AbstractClass() {
.....
update();
....
}
protected void update() {
.....
}
}
在从ConcreteClass调用super并从PreConcreteClass调用super之后调用ConcreteClass的重写更新方法时抛出NPE。原因是internalDS - 它为null,导致for循环抛出NPE。
首先 - 这与我一直期望的一样 - 在声明初始化的类字段在执行构造函数的范围之前被初始化。通过super?
调用派生类的构造函数时不是这种情况第二 - 我通过添加一个由AbstractClass构造函数调用的init方法来解决NPE,该方法由AbstractClass给出一个空实现,并由ConcreteClass在internalDS上初始化进行覆盖。
我查了一些一般性建议in stack overflow。 我和我的同事在工作中进行了一些讨论,我们一致同意上面的设计存在遗传问题,这导致了NPE。 由于这是我们不想彻底改变的遗留代码,因此我想知道是否有人有更好的替代我使用的init方法解决方案。 注意 - 每个类都有多个构造函数。
答案 0 :(得分:1)
不,编译器在调用super之后在构造函数中移动那些初始化程序,因此您的代码等同于:
public class ConcreteClass extends PreConcreteClass{
private List<Object> internalDS;
public ConcreteClass() {
super();
internalDS = new ArrayList<>();
...
}
@Override
protected void update() {
....
for(Object o : internalDS) {
...
}
...
}
请注意,有一个通用规则可以更清晰地避免这种情况:从不在构造函数中调用非final方法。它可以搞砸了。