为什么当我说新的House(“x”)时会调用超类构造函数Building()?

时间:2015-02-04 15:59:44

标签: java oop inheritance

我有以下代码,但我不明白为什么当我运行它时会在打印"b"之前打印"h hn x"。为什么"b"完全打印,因为我执行Building时根本没有调用超类House()

class Building {
    Building() {
        System.out.print("b ");
    }

    Building(String name) {
        this();
        System.out.println("bn " + name);
    }
}

public class House extends Building {
    House() {
        System.out.println("h ");
    }

    House(String name) {
        this();
        System.out.println("hn " + name);
    }

    public static void main(String[] args) {
        new House("x ");
    }
}

5 个答案:

答案 0 :(得分:5)

超类的零参数构造函数由其子类的构造函数自动隐式调用。

更一般地说,

class B extends A

构造函数

public B()
{
    //Your code
}

实际上看起来像

public B()
{
    super(); //Call the superclass constructor
    //Your code
}

您可以通过对某些其他超类构造函数进行显式调用来覆盖此行为。请注意,如果无法对构造函数进行隐式调用(如果您的no-arg构造函数不存在),那么您将看到错误。

答案 1 :(得分:3)

每当构造子类时,总是调用超类构造函数。如果超类构造函数不需要任何参数(如此处所示),则可以隐式进行此调用。

如果你要在构造函数中引入一个参数,你会在House中遇到一个错误,因为它需要你显式调用新的超类构造函数。

答案 2 :(得分:3)

官方资源:

来自Oracle javase tutoriel:

  

使用super(),调用超类无参数构造函数。同   super(parameter list),具有匹配的超类构造函数   参数列表被调用。注意:如果构造函数没有显式   自动调用超类构造函数,Java编译器   插入对超类的无参数构造函数的调用。如果   超类没有无参数构造函数,你会得到   编译时错误。 Object确实有这样的构造函数,所以如果   Object是唯一的超类,没有问题。

     

如果子类构造函数调用其超类的构造函数,   无论是明示还是暗示,您可能会认为会有一个   整个构造函数链被称为,一直回到   Object的构造函数。事实上,情况就是这样。它被称为   构造函数链接,当有一个时,你需要知道它   班级下降。

其他资源:

构造函数链接部分从SCJP 6书中以简单的方式清楚地解释了您正在寻找的内容,它还提供了有关此过程的更多信息:

  

我们知道当你说新的时,会在运行时调用构造函数   一些类的类型如下:Horse h = new Horse();但真的是什么   当你说new Horse()时会发生什么? (假设Horse extends Animal和   Animal extends Object。)

     
      
  1. Horse构造函数被调用。每个构造函数都调用其超类的构造函数,并对super()进行(隐式)调用,   除非构造函数调用相同的重载构造函数   上课(一分钟内更多)。
  2.   
  3. Animal构造函数被调用(AnimalHorse的超类。)
  4.   
  5. Object构造函数被调用(Object是所有类的最终超类,因此类Animal扩展Object即使你没有   实际上在"extends Object"类声明中键入Animal。它' S   隐含的。)此时我们处于堆栈顶部。
  6.   
  7. Object个实例变量的显式值。通过显式值,我们指的是在时间分配的值   变量被声明,如"int x = 27",其中"27"是显式的   实例变量的值(与默认值相对)。
  8.   
  9. Object构造函数完成。
  10.   
  11. Animal实例变量的显式值(如果有)。
  12.   
  13. Animal构造函数完成。
  14.   
  15. Horse实例变量的显式值(如果有)。
  16.   
  17. Horse构造函数完成。
  18.   

与你的例子类比:

所以当你说new House("x ")时,会发生以下情况:

  1. House(String name)按关键字House()的指定调用this()
  2. House()构造函数隐式调用super(),它调用construcotr Building()
  3. Building()构造函数隐式调用super() Object构造函数。
  4. Object构造函数完成
  5. Building()构造函数将完成并打印"b "
  6. House()构造函数将完成并打印"h"
  7. House(String name)构造函数将完成并打印"hn x "
  8. 结果为"b h hn x "
  9. NB:如果您从Building(String name)添加了显式调用House(),则会调用 super("someString"),在这种情况下,结果将为:{{1 }}

答案 3 :(得分:1)

在继承中,有必要首先初始化超类中存在的所有字段,因为这些字段是在子类中使用的,为此,在构造子类超类构造函数之前调用它来初始化超类中存在的所有字段类。

构造子类实例时调用的超类构造函数。在您的代码中,您正在创建new House("x "); House的实例。

此时调用House参数化构造函数House(String name)会调用超类隐式构造函数。

答案 4 :(得分:1)

如果你单步执行程序,调用堆栈会显示正在讨厌的内容:

(你需要从下到上跟随调用堆栈):

House(Building).<init>() line: 3

House.<init>() line: 2
House.<init>(String) line: 7
House.main(String[]) line: 12

  1. First Main被称为
  2. 然后在House(name)构造函数中,this()被称为
  3. 这会调用House()构造函数(因为没有提供参数)
  4. 现在有了一个有趣的部分:因为默认构造函数被调用而House是从Building派生的,所以需要先构建Building,然后按规范构建父类Building的默认构造函数。