父类可以创建其子类的实例吗?

时间:2020-10-26 13:13:11

标签: java inheritance sonarqube

我在一些Java代码上使用Sonarqube进行了单元测试,发现的问题之一如下。

类在初始化期间不应访问自己的子类

当父类在其自身的初始化期间引用子类的成员时,结果可能不是您期望的,因为子类可能尚未初始化。这可能会导致所谓的“初始化周期”,甚至在某些极端情况下甚至会导致僵局。

这是Sonarqube用于描述问题的示例代码:

class Parent {
  static int field1 = Child.method(); // Noncompliant
  static int field2 = 42;

  public static void main(String[] args) {
    System.out.println(Parent.field1); // will display "0" instead of "42"
  }
}

class Child extends Parent {
  static int method() {
    return Parent.field2;
  }
}

接下来是引发问题的代码的简化。

abstract class Parent {
    static Parent childInstance = new Child();
}

我真的不明白为什么这是一个问题。在Sonarqube示例中,父级通过调用子级的静态方法来初始化field1。这意味着我不需要在调用该方法之前实例化一个孩子。

在第二段代码中,父级试图实例化子级,而不是调用其方法之一。

您能给我解释一下为什么无法在父类中引用孩子吗?

编辑:我正在将SonarScanner用于Maven,我的Sonarqube版本是8.4.1.35646。问题的规则ID为S2390。

1 个答案:

答案 0 :(得分:0)

在这里考虑何时执行代码:

abstract class Parent {
    static Parent childInstance = new Child();
}

自从您分配给static字段以来,必须在创建第一个new Child()实例之前很久执行Parent

即在类初始化期间(为简单起见,我们假设这与“类加载”等效,即使它不太准确)。

这意味着在初始化类Parent时,它将创建一个Child的新实例。通常,完成初始化需要发生的第一件事是超类已经初始化。由于我们当前正在初始化Parent,所以我们可以知道Child尚未完全初始化(根据定义,因为这将需要Parent完全初始化)。

JVM / Java语言规范发挥了一些“技巧”,实际上可以使这种构造起作用,但是它们也有缺点(例如,能够观察未初始化的final字段)。

这样想:您正忙着建造地下室时尝试从房子的第二层楼中抢走一些东西。