为什么构造函数中不能同时使用this()
和super()
?
为什么要这样规定呢?
为什么构造函数中不能同时使用this()
和super()
?
为什么要这样规定呢?
this(...)
会调用同一类中的另一个构造函数,而super()
会调用超类的构造函数。如果在构造函数中没有使用super()
,编译器将隐式地添加一个。
因此,如果两者都允许,则可能会调用super
构造函数两次。
示例(不要在参数中寻找意义):
class A {
public A() {
this( false );
}
public A(boolean someFlag) {
}
}
class B extends A {
public B() {
super();
}
public B( boolean someFlag ) {
super( someFlag );
}
public B ( int someNumber ) {
this(); //
}
}
现在,如果你调用 new B(5)
,将会调用以下构造函数:
this( false);
A() ---------------> A(false)
^
|
| super();
|
| this();
B() <--------------- B(5) <--- you start here
更新:
如果你能够使用this()
和super()
,你可能会得到像这样的东西:
(注意: 这只是为了展示可能出现的问题,如果您被允许这样做的话 - 幸运的是您不能这样做)
this( false);
A() ---------------> A(false)
^ ^
| |
| super(); | super( true ); <--- Problem: should the parameter be true or false?
| |
| this(); |
B() <--------------- B(5) <--- you start here
正如您所看到的,您将遇到一个问题,即可以使用不同的参数调用A(boolean)
构造函数,现在您必须决定使用哪个。此外,其他构造函数(A()
和B()
)可能包含代码,现在可能不会正确调用(即顺序不对等),因为对super(true)
的调用将规避它们,而对this()
不会。
super()
和 this()
之间有区别。
super()
- 调用基类构造函数,而
this()
- 调用当前类构造函数。
两者均为构造函数调用。
构造函数调用必须始终是第一条语句。 所以你只能将 super()
或 this()
作为第一条语句之一。
两者都必须在你使用的构造函数的第一行中声明。这就是为什么我们不能在单个构造函数中同时使用两者的原因,因为你只能在第一行中写一个东西。
this()
和super()
都是构造函数调用,构造函数调用必须是构造函数中第一个(且仅为第一个)调用。否则,在实例化单个对象时将会多次调用Object
构造函数。
构造函数中不能同时使用this()和super()。
this()用于调用同一类的默认构造函数,应该是构造函数中的第一条语句。
super()用于调用基类的默认构造函数,应该是构造函数中的第一条语句。
因此,this()和super()都用于构造函数调用,但都希望在首位执行。这就是为什么会显示编译器错误:
错误:调用this必须是构造函数中的第一条语句 this(); 或者
错误:调用super必须是构造函数中的第一条语句 super();
因为这没有意义。构造函数必须调用this()
或super()
(隐式或显式)。this()
调用另一个构造函数,该构造函数必须像以前一样调用this()
或super()
等等。调用this()
和super()
的构造函数最终会调用super()
两次。
this()
和super()
,会导致编译时错误。因为this()
和super()
必须是第一个可执行的语句。如果您首先编写this()
,那么super()
将成为第二个语句,反之亦然。这就是为什么我们不能同时使用this()
和super()
的原因。比较下面的例子。FirstChild类在两个构造函数中设置实例变量名称,因为第一个构造函数调用第二个构造函数被排除了,需要调用super()。
在SecondChild类中引入了第三个私有构造函数,它接受2个参数-第一个传递给supper(),第二个用于设置名称。前两个构造函数都调用第三个构造函数。Super()仅被调用一次,实例变量也仅在一个构造函数中设置。代码产生相同的结果,无需在同一个构造函数中调用super()和this()。
class FirstChild extends ConstructorTest{
private String name = null;
public FirstChild(){
super("super text 1");
//this("Unknown"); //UNCOMMENTED DOES NOT COMPILE
name = "Unknown";
}
public FirstChild(String name){
super("super text 2");
this.name = name;
}
public String getName(){
return name;
}
}
class SecondChild extends ConstructorTest{
private String name = null;
public SecondChild(){
this("super text 1", "Unknown");
}
public SecondChild(String name){
this("super text 2", name);
}
private SecondChild(String superStr, String name)
{
super(superStr);
this.name = name;
}
public String getName(){
return name;
}
}
public class ConstructorTest{
public ConstructorTest(String str){
System.out.println("ConstructorTest constructor called with parameter \"" + str + "\"");
}
public static void main(String... args)
{
System.out.println("Hello from main, FirstChild results:");
FirstChild fc1 = new FirstChild();
FirstChild fc2 = new FirstChild("John");
System.out.println(" child fc1 name: " + fc1.getName());
System.out.println(" child fc2 name: " + fc2.getName());
System.out.println("Hello from main, SecondChild results:");
SecondChild sc1 = new SecondChild();
SecondChild sc2 = new SecondChild("John");
System.out.println(" child sc1 name: " + sc1.getName());
System.out.println(" child sc2 name: " + sc2.getName());
}
}
super() - 指的是直接父类实例。 可用于调用直接父类方法。 this() - 指的是当前类实例。 可用于调用当前类方法。
由于构造函数调用必须是方法中的第一条语句,因此如果我们在一个方法中同时定义了this和super构造函数,那么就会发生冲突,如下所示。 假设首先调用此构造函数,则它将检查当前类构造函数,如果在当前类构造函数中有另一个方法调用或语句,则在此调用中,在调用超类构造函数之前将调用当前类构造函数内的所有方法和语句,然后将拒绝“构造函数调用必须是方法中的第一条语句”的语句。