有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

在处理我公司的遗留代码时,我在运行时遇到了一个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() {
       .....
    }
}

NPE是在从ConcreteClass调用super和从PreConcreteClass调用super之后,在调用ConcreteClass的重写更新方法时抛出的。原因是internalDS——它为空,导致for循环抛出NPE

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

第二,我通过添加一个init方法解决了NPE问题,该方法由AbstractClass构造函数调用,AbstractClass为其提供了一个空的实现,并由ConcreteClass在internalDS上进行初始化来覆盖

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


共 (1) 个答案

  1. # 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方法。它会把事情搞砸的