在 Java 中何时以及如何调用超级构造函数



我试图在链式构造函数中使用this()super()来理解构造函数的执行顺序。我尝试了以下代码:

public class ConstructorChaining{
public static void main(String args[]) {
new CCC();
}
} 
class CCA
{
public CCA() {
this("");
System.out.println("Inside A()");
}
public CCA(String a) {
System.out.println("Inside A(String)");
}
}
class CCB extends CCA 
{
public CCB() {
this("");
System.out.println("Inside B()");
}
public CCB(String a) {
//this(2);
System.out.println("Inside B(String)");
}
public CCB(int a) {
System.out.println("Inside B(int)");
}
}
class CCC extends CCB 
{
public CCC() {
this("");
System.out.println("Inside C()");
}
public CCC(String a) {
this(5);
System.out.println("Inside C(String)");
}
public CCC(int a) {
System.out.println("Inside C(int)");
}
}

这将打印以下内容:

Inside A(String)
Inside A()
Inside B(String)
Inside B()
Inside C(int)
Inside C(String)
Inside C()

所以我觉得:

如果一个类的构造函数重载没有显式调用super(),那么它所有链接的构造函数重载将被执行,然后隐式调用super(),而又遵循相同的模式。

换句话说,在执行子类的所有链式构造函数重载之后,最终会对父级的默认构造函数进行隐式调用。从图表上看,

CO1() --this()--> CO2() --this()--> ... --this()--> COn              Constructor Overloads (CO) of Class Cn 
|
Implicit super() call
|
v
COn() <--this()-- ... <--this()-- CO2() <--this()-- CO1              Constructor Overloads (CO) of Class Cn-1 which Cn's parent
|
Implicit super() call
|
v
:
|
Implicit super() call
|
v    
CO1() --this()--> CO2() --this()--> ... --this()--> COn              Constructor Overloads (CO) of Class C1 which is C2's parent

如果我的这个观察是正确的,那么我的疑问是谁决定在执行当前类的所有链式构造函数后最终隐式调用super()?另外,这个决定/行为是如何在 jdk/jre 中实现的?编译器是否生成字节码并最后一次调用super()或运行时动态决定调用super()

如果没有类的构造函数重载显式调用 super(),则其所有链式构造函数重载都将执行,然后隐式调用 super(),而 super() 又遵循相同的模式。

不對。

如果构造函数不以this(...)super(...)开头,则编译器会插入一个隐式的 no-argsuper()。这绝不取决于超载。

就是这样。真的就是这么简单。最终调用超级构造函数不需要整体逻辑。

这也正是您的图表所显示的。是构造函数COn调用super(),因为编译器添加了它。如果一个调用的所有构造函数都有一个this(...)super(...),则永远不会调用 no-argsuper()

是的!JVM做了很多这样的事情!你可能想知道为什么JVM这样做?真的有必要吗?好吧,要找出原因,请考虑以下代码:

class A{
int a;
A(int value){ 
a = value
}
}
class B extends A{
int b;
B(int value){
b = value;
}
}

如果编译此代码,将收到编译错误,指出:"A 中没有可用的默认构造函数" 那是因为JVM不知道该给a什么价值。您可能会说int的默认值为 0,但如果A有一个对象字段并且必须在使用前在构造函数中初始化它怎么办?因此,JVM强制您在第一行调用supper类的构造函数,或者它隐式调用默认构造函数(如果没有默认构造函数,则会抛出错误)。

最新更新