在处理公司的遗留代码时,我在运行时遇到了 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 - 它为空,导致for循环抛出NPE。
首先 - 这与我一直期望的相反 - 在声明时初始化的类字段在执行构造函数的范围之前初始化。通过 super 调用派生类的构造函数时不是这样吗?
第二 - 我通过添加一个由 AbstractClass 构造函数调用的 init 方法解决了 NPE,该方法由 AbstractClass 给出了一个空实现,并被 ConcreteClass 通过内部 DS 上的初始化覆盖。
我查阅了一些一般建议in stack overflow 。 我在工作中与同事进行了一些讨论,我们一致认为上述设计存在继承问题,导致了 NPE。 由于这是我们不想彻底更改的遗留代码,因此我想知道是否有人有更好的替代方案来替代我使用的 init 方法解决方案。 注意 - 每个类都有多个构造函数。
最佳答案
不,编译器在调用 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方法。它会把事情搞砸。
关于java - 通过声明初始化类 DS 字段 - 在构造函数调用之前还是之后?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48961601/