通过声明初始化类DS字段 - 在构造函数调用之前或之后?

时间:2018-02-24 10:06:42

标签: java oop initialization

在处理我公司的遗留代码时,我在运行时遇到了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方法解决方案。 注意 - 每个类都有多个构造函数。

1 个答案:

答案 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方法。它可以搞砸了。