繁体   English   中英

与隐式构造函数和构造函数链接相关的混淆

[英]confusion related to implicit contructors and constructor chaining

当创建派生类对象并将其分配给基类引用时,应根据构造函数链接基构造函数。 并且基类中没有默认构造函数,但有一个显式参数化构造函数,因此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);
    }
}

Java 语言规范(第12.5 节)定义了创建新实例时会发生什么; 我强调了你的问题最重要的部分。

  1. 如果此构造函数以同一类另一个构造函数的显式构造函数调用(第 8.8.7.1 节)开始(使用 this),则评估参数并使用相同的五个步骤递归处理该构造函数调用。 如果构造函数调用突然完成,那么这个过程也会因为同样的原因突然完成; 否则,继续步骤 5

  2. 此构造函数不以对同一类中另一个构造函数的显式构造函数调用开始(使用 this)。 如果此构造函数用于 Object 以外的类,则此构造函数将以显式或隐式调用超类构造函数(使用 super)开始 使用这五个相同的步骤,递归地评估超类构造函数调用的参数和过程。 如果该构造函数调用突然完成,则此过程出于同样的原因而突然完成。 否则,继续第 4 步。

所以,关键点是:

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

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

通过添加

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

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

如果你想保留默认构造函数,你可以像这样自己写:

public Parent(){
}

下面的构造函数

public Child(){

}

将自动替换为

public Child(){
    super();
}

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

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

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

因为如果您不将this()添加到Child()构造函数中 - 编译器将插入super()语句,因此期望在Parent类中使用 no-arg 构造函数。

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);
    }
}

按照构造函数链接,当创建派生类对象并将其分配给基类引用时,应调用基本构造函数。 而且在基类中没有默认的构造函数,但是有一个显式的参数化构造函数,因此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);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM