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

Can a parent class create an instance of its subclass?

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

Classes should not access their own subclasses during initialization

When a parent class references a member of a subclass during its own initialization, the results might not be what you expect because the child class might not have been initialized yet. This could create what is known as an "initialisation cycle", or even a deadlock in some extreme cases.

这是 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。这意味着我不需要在调用方法之前实例化子对象。

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

你能给我解释一下为什么不能在父项中引用子项吗class?

编辑:我正在为 Maven 使用 SonarScanner,我的 Sonarqube 版本是 8.4.1.35646。问题规则id为S2390.

想想这里代码执行的时候:

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

由于您分配给 static 字段,new Child() 必须在创建第一个 Parent 实例之前很久就执行。

即在 class 初始化期间(为简单起见,假设这等同于“class 加载”,尽管这并不十分准确)。

这意味着在初始化 class Parent 时,它会创建一个新的 Child 实例。通常要完成初始化需要发生的第一件事是 super class 已经初始化。由于我们目前正在初始化 Parent,我们可以知道 Child 还不能完全初始化(根据定义,因为这需要 Parent 才能完全初始化)。

JVM/Java 语言规范使用了一些“技巧”来实际允许此构造工作,但它们也有缺点(例如能够观察未初始化的 final 字段)。

这样想:你正忙着建造地下室,却想从房子的二楼拿东西。