我有以下代码,但我不明白为什么当我运行它时会在打印"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 ");
}
}
答案 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
。)
Horse
构造函数被调用。每个构造函数都调用其超类的构造函数,并对super()
进行(隐式)调用, 除非构造函数调用相同的重载构造函数 上课(一分钟内更多)。Animal
构造函数被调用(Animal
是Horse
的超类。)Object
构造函数被调用(Object
是所有类的最终超类,因此类Animal
扩展Object
即使你没有 实际上在"extends Object"
类声明中键入Animal
。它' S 隐含的。)此时我们处于堆栈顶部。Object
个实例变量的显式值。通过显式值,我们指的是在时间分配的值 变量被声明,如"int x = 27"
,其中"27"
是显式的 实例变量的值(与默认值相对)。Object
构造函数完成。Animal
实例变量的显式值(如果有)。Animal
构造函数完成。Horse
实例变量的显式值(如果有)。- 醇>
Horse
构造函数完成。
所以当你说new House("x ")
时,会发生以下情况:
House(String name)
按关键字House()
的指定调用this()
。House()
构造函数隐式调用super()
,它调用construcotr Building()
。 Building()
构造函数隐式调用super()
Object
构造函数。Object
构造函数完成Building()
构造函数将完成并打印"b "
House()
构造函数将完成并打印"h"
House(String name)
构造函数将完成并打印"hn x "
。"b h hn x "
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