与隐式构造函数和构造函数链接有关的混乱

时间:2020-02-14 19:19:59

标签: java

按照构造函数链接,当创建派生类对象并将其分配给基类引用时,应调用基本构造函数。 而且在基类中没有默认的构造函数,但是有一个显式的参数化构造函数,因此java编译器不提供默认的构造函数。 没有陈述“ this(10);”编译器抱怨,但是一旦添加它,编译器就可以了。为什么?
我的意思是为什么它在添加“ this(10);”之后不尝试调用基类的默认构造函数。它应该做一个超级调用,然后执行添加的语句。

class Parent{
    public Parent(int a) {
        System.out.println(a);
    }
}
class Child extends Parent{
    public Child(){
        this(10);//default value
    }
    public Child(int a) {
        super(a);
        System.out.println(a);
    }
}

4 个答案:

答案 0 :(得分:2)

Java语言规范(§12.5)定义了创建新实例时发生的情况;我强调了您的问题中最重要的部分。

  1. 如果此构造函数以显式构造函数调用(第8.8.7节)开始(<8.8>同一类中的另一个构造函数)(使用此方法),则求值并递归处理该构造函数调用使用相同的五个步骤。如果该构造函数调用突然完成,则出于相同原因,此过程也会突然完成;否则,继续执行步骤5

  2. 此构造函数并不以相同类中的另一个构造函数的显式构造函数调用开头(使用此函数)。如果此构造函数用于Object以外的其他类,则该构造函数将以显式或隐式调用超类构造函数(使用super)开头。使用这五个步骤来递归评估超类构造函数调用的参数和过程。如果该构造函数调用突然完成,则出于相同原因,此过程也会突然完成。否则,请继续执行步骤4。

因此,关键点是:

  • 您的第一个构造函数显式调用了第二个构造函数,因此上面的步骤2适用;执行第二个构造函数,然后跳过
  • 第3步是调用超类构造函数的地方,这意味着当一个构造函数从同一个类调用另一个构造函数时,它不会直接调用超类构造函数。
  • 但是,如果您从第一个构造函数中删除this(10);,则第一个构造函数不会调用同一类的另一个构造函数,因此将应用步骤3,并且隐式调用超类构造函数。这会导致错误,因为没有可以隐式调用(没有参数)的超类构造函数。

答案 1 :(得分:0)

仅当没有其他构造函数时,默认/隐式构造函数才存在。

通过添加

public Parent(int a) {
    System.out.println(a); 
}

您删除了Parent的默认构造函数。

如果要保留默认构造函数,可以这样编写:

public Parent(){
}

以下构造函数

public Child(){

}

将自动替换为

public Child(){
    super();
}

如果第一行中没有构造函数调用(this()super()),则会发生这种替换。

这样可以确保在任何情况下都可以调用超级构造函数。

如果超类中没有没有参数的构造函数(如果您已将默认构造函数替换为参数化构造函数),则替换将失败。

答案 2 :(得分:0)

因为如果不向this()构造函数中添加Child(),则编译器将插入super()语句,并因此在Parent类中使用无参数构造函数。

class Parent{
    public Parent(int a) {
        System.out.println(a);
    }
}
class Child extends Parent{
    public Child(){
        // this(10);// Commenting this(10) as if it did not exist.
        super() // inserted by compiler unless you put this() or super() yourself
    }
    public Child(int a) {
        super(a);
        System.out.println(a);
    }
}

答案 3 :(得分:0)

没有语句“ this(10);”编译器抱怨

Parent中添加以下no-arg构造函数,并且如果没有this(10);中的Child(){},编译器将不会抱怨

public Parent() {
    //...
}

该问题的另一种解决方案是从Child删除no-arg构造函数,即删除

public Child(){
    // ...
}

只要子类中没有no-arg构造函数,编译器就不会抱怨将其包含在父类中。但是,一旦将一个添加到子类中,则也必须在父类中添加它。

相关问题