【问题标题】:Initializing class DS field via declaration - before or after constructor invocation?通过声明初始化类 DS 字段 - 在构造函数调用之前还是之后?
【发布时间】:2018-02-24 10:06:41
【问题描述】:

在处理我公司的遗留代码时,我在运行时遇到了 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 的覆盖更新方法时抛出 NPE,在从 ConcreteClass 调用 super 和从 PreConcreteClass 调用 super 之后。原因是 internalDS - 它为 null,导致 for 循环抛出 NPE。

首先 - 这与我一直期望的相反 - 在声明时初始化的类字段在执行构造函数的范围之前被初始化。通过 super 调用派生类的构造函数时不是这样吗?

第二 - 我通过添加一个由 AbstractClass 构造函数调用的 init 方法解决了 NPE,该构造函数由 AbstractClass 给出一个空实现,并由具有 internalDS 初始化的 ConcreteClass 覆盖。

我查找了一些一般性建议 in stack overflow。 我在工作中与我的同事进行了一些讨论,我们一致认为上述设计存在继承问题,导致 NPE。 由于这是我们不想彻底改变的遗留代码,我想知道是否有人有更好的替代方法来替代我使用的 init 方法解决方案。 注意 - 每个类都有多个构造函数。

【问题讨论】:

    标签: java oop initialization


    【解决方案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) {
             ...
          }
          ...
    }
    

    请注意,有一条通用规则可以以更简洁的方式避免这种情况:从不在构造函数中调用非最终方法。它可以把事情搞砸。

    【讨论】:

    • 正如我所怀疑的那样。除了在 AbstractClass 中使用 init 方法之外,对初始化 DS 的更好解决方案有什么想法吗?
    • 除了一般的设计缺陷之外,使用 init 方法似乎没问题。整个设计在某种程度上被破坏了,但是如果您不想对其进行任何更大的更改,则可以使用 init 方法。另见stackoverflow.com/questions/3404301/…
    猜你喜欢
    • 2011-03-28
    • 1970-01-01
    • 2011-06-24
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 1970-01-01
    • 2016-02-22
    • 2019-07-09
    相关资源
    最近更新 更多