简体   繁体   English

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

[英]Initializing class DS field via declaration - before or after constructor invocation?

When working on my company's legacy code, I encountered an NPE during runtime. 在处理公司的遗留代码时,我在运行时遇到了NPE。 After debugging it, this is what I encountered : 调试之后,这就是我遇到的问题:

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() {
       .....
    }
}

The NPE was thrown when the overriding update method of the ConcreteClass was invoked, after the invocation of super from ConcreteClass and super from PreConcreteClass. 在调用ConcreteClass的super和PreConcreteClass的super之后,调用ConcreteClass的重写更新方法时会引发NPE。 The cause was internalDS - it was null, causing the for loop to threw the NPE. 原因是internalDS-它为空,导致for循环引发NPE。

First - this is against what I have always expected - that class fields which have been initialized at declaration are initialized before executing the constructor's scope. 首先-这违反了我一直期望的-在执行构造函数的作用域之前,初始化了在声明时初始化的类字段。 Is this not the case when calling the constructors of derived classes via super ? 通过super调用派生类的构造函数时不是这种情况吗?

Second - I solved the NPE by adding an init method which is called by the AbstractClass constructor, which is given an empty implementation by AbstractClass, and is overridden by the ConcreteClass with the initialization on internalDS. 第二-我通过添加一个由AbstractClass构造函数调用的init方法解决了NPE,该方法由AbstractClass给出了一个空的实现,并被ConcreteClass覆盖,并在internalDS上进行了初始化。

I looked up some general advise in stack overflow . 在堆栈溢出中查找了一些一般性建议。 I had some discussions with my colleagues at work where we agreed that there is an inherit problem with the design above which caused the NPE. 我与工作中的同事进行了一些讨论,我们同意上面的设计存在一个继承问题,从而导致了NPE。 Since this is legacy code which we do not want to drastically change, I waned to know if anyone has a better alternative to the init method solution I used. 由于这是我们不想彻底更改的遗留代码,因此我想知道是否有人可以替代我使用的init方法解决方案。 Note - there are multiple constructors for each class. 注意-每个类都有多个构造函数。

No, the compiler is moving those initializer in the constructor after the call to super, so your code is equivalent to that: 不,编译器在调用super之后将构造函数中的那些初始值设定项移动,因此您的代码等效于:

public class ConcreteClass extends PreConcreteClass{
   private List<Object> internalDS;
   public ConcreteClass() {
      super();
      internalDS = new ArrayList<>();
      ...
   }
   @Override
   protected void update() {
      ....
      for(Object o : internalDS) {
         ...
      }
      ...
}

Note that there is a general rule to avoid that in a cleaner way: Never call non-final methods in a constructor. 请注意,有一条通用规则可以避免这种情况: 永远不要在构造函数中调用非最终方法。 It can screw things up. 它会使事情搞砸。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM