根据Java tutorial on constructors:
你不必为你的班级提供任何建设者,但是你 这样做时一定要小心。编译器自动提供 无参数,没有构造函数的任何类的默认构造函数。 这个默认构造函数将调用的无参数构造函数 超类。在这种情况下,编译器会抱怨如果 超类没有无参数构造函数,所以你必须验证 它确实如此。如果你的类没有明确的超类,那么它有一个 Object的隐式超类,它有一个无参数 构造
如果您的超类 A 没有明确的默认构造函数,则 子类 B 扩展A ,没有明确的默认构造函数,
在驱动程序类的主要方法中你做了
A obj1 = new A();
将创建一个默认构造函数,它将调用Object类的默认构造函数,是否正确?
但如果你这样做
B obj2 = new B();
根据教程,将生成B的默认构造函数,并且构造函数将调用超类的无参数构造函数,以便在Object中调用构造函数。
那么超类什么时候没有无参数构造函数?
答案 0 :(得分:5)
默认构造函数由编译器在您未提供时定义。
所以这个
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
的默认构造函数。
<强>&GT;那么什么时候超类没有无参数构造函数呢?
当您明确定义一个时,它将没有no-arg构造函数。例如,如果我将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 Decompiler Demonstration
事实上,您可以使用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);
}
这表明您在原始问题中引用的规范中所读到的内容是正确的。
答案 1 :(得分:1)
那么超类什么时候没有无参数构造函数?
如果添加任何其他超类构造函数但忘记添加no-arg构造函数,编译器会抱怨。在这种情况下,不提供超类的默认构造函数。
答案 2 :(得分:0)
在驱动程序类的
main
方法中A obj1 = new A();
将创建默认构造函数
在驱动程序的main
方法中,您无法创建默认构造函数。如果已定义,则可以使用它;如果没有定义,则会出现编译错误。
那么超类什么时候没有无参数构造函数?
当它有其他构造函数时,所有构造函数都使用一些参数。这是一个例子:
class SuperA {
public SuperA(String str) { ... }
public SuperA(int num) { ... }
}
上面,SuperA
有两个构造函数 - 一个使用String
,另一个使用int
。它们都不是默认值,因为它们采用参数。
如果创建派生类DerivedB extends SuperA
并且没有定义任何构造函数,则会出现编译错误。