默认构造函数在你不提供时由编译器定义。
所以这个
public class A{}
编译器会表示为:
public class A
public A() {
super(); //invokes Object's default constructor
}
}
由于我对A 的定义没有定义显式构造函数。
在上面的示例中,A 隐式扩展了Object,而Object's 默认构造函数在super() 执行时由编译器自动调用。对于任何可能扩展 A 的类也是如此,例如:
public class B extends A {}
将由编译器实现,有点像:
public class B extends A {
public B() {
super(); //invokes A's default constructor
}
}
如您所见,最终会链接Object 的默认构造函数,然后是A 的默认构造函数,最后是B 的默认构造函数。
> 那么超类什么时候会没有无参数构造函数呢?
当您明确定义一个无参数构造函数时,它不会有。例如,如果我将A 的定义更改为
public class A {
public A(String name){}
}
然后A 不再有默认构造函数,我不能再这样做了
public class B extends A {
//Uh oh, compiler error.
//Which parent class constructor should the compiler call?
}
现在B 必须通过明确说明要使用哪个构造函数,从其父类中显式链接正确的构造函数。例如
public class B extends A {
B() {
super("B"); //Now the compiler knows which constructor to invoke
}
}
Java 反编译器演示
实际上,您可以使用 JDK 附带的工具来演示所有这些。在您的 JDK bin 目录中有一个名为 javap 的程序。这是 Java Decompiler 工具,可以让您查看编译器生成的代码。
您可以编译我的示例,然后反编译它们以查看生成的代码,例如
javac A.java
javap A
反编译器会告诉你:
public class A {
A();
}
这清楚地表明编译器添加了一个默认构造函数。
你可以反汇编类来查看字节码。
javac B.java
javap -c B
它会显示它是如何调用父类默认构造函数的
class B extends A {
B();
Code:
0: aload_0
1: invokespecial #1 // Method A."<init>":()V
4: return
}
如果我给A的构造函数添加一个默认参数,你会看到编译器不再提供默认构造函数,它只是提供了我明确定义的那个:
class A {
A(String name){}
}
那我就可以了
javac A.java
javap A
它会产生
class A {
A(java.lang.String);
}
这表明您在原始问题中引用的规范中阅读的内容是正确的。