如果在构造函数中使用super调用重写的方法会发生什么 [英] What happens if you call an overridden method using super in a constructor
问题描述
有两个类 Super1
和 Sub1
There is two classes Super1
and Sub1
Super1.class
Super1.class
public class Super1 {
Super1 (){
this.printThree();
}
public void printThree(){
System.out.println("Print Three");
}
}
Sub1.class
Sub1.class
public class Sub1 extends Super1 {
Sub1 (){
super.printThree();
}
int three=(int) Math.PI;
public void printThree(){
System.out.println(three);
}
public static void main(String ...a){
new Sub1().printThree();
}
}
当我调用方法我希望输出为类
: Sub1
的printThree
When I invoke the method printThree
of class Sub1
I expected the output to be:
打印三张
3
Print Three
3
因为 Sub1
构造函数,调用 super.printThree();
。
但我实际上得到了
0
打印三张
3
0
Print Three
3
我知道0是 int
的默认值,但是它是如何发生的?
I know 0 is default value of int
but how it is happening ?
推荐答案
您正在看到三件事的影响:
You're seeing the effects of three things:
-
默认的超级构造函数调用,以及
Default super-constructor calls, and
实例初始化程序(相对于超级调用),以及
Instance initializers relative to super calls, and
重写的方法如何工作
您的 Sub1
构造函数是真的:
Sub1(){
super(); // <== Default super() call, inserted by the compiler
three=(int) Math.PI; // <== Instance initializers are really inserted
// into constructors by the compiler
super.printThree();
}
(令人惊讶,我知道,但这是事实。请使用 javap -c YourClass
来查看。:-))
(Surprising, I know, but it's true. Use javap -c YourClass
to look. :-) )
原因看起来就是在子类可以初始化对象的其部分之前,超类必须有机会初始化其对象 。这样便得到了这种交织效果。
The reason it looks like that is that the superclass must have a chance to initialize its part of the object before the subclass can initialize its part of the object. So you get this kind of interwoven effect.
鉴于这就是 Sub1
真正的
And given that that's what Sub1
really looks like, let's walk through it:
-
JVM会创建实例并将所有实例字段设置为默认值(所有位)关闭)。因此,此时,
三个
字段存在,并且值<< c $ c> 0 。
JVM调用 Sub1
。
Sub1
立即调用 super()
( Super1
),这会... / p>
Sub1
immediately calls super()
(Super1
), which...
-
...调用
printThree
。由于printThree
被覆盖,即使对它的调用在Super1
的代码中,也被覆盖方法(Sub1
中的一个)被调用。这是Java实现多态的一部分。由于三个
的实例初始化器尚未运行,因此三个
包含0
,这就是输出。
...calls
printThree
. SinceprintThree
is overridden, even though the call to it is in the code forSuper1
, it's the overridden method (the one inSub1
) that gets called. This is part of how Java implements polymorphism. Sincethree
's instance initializer hasn't been run yet,three
contains0
, and that's what gets output.
Super1
返回。
返回 Sub1
,它是<$的实例初始化代码c $ c>三个,编译器插入(确实已重定位)运行,并为三个
提供一个新值。
Back in Sub1
, the instance initializer code for three
that the compiler inserted (relocated, really) runs and gives three
a new value.
Sub1
调用 printThree
。由于三个
的实例初始化程序代码现已运行,因此 printThree
打印 3
。
Sub1
calls printThree
. Since three
's instance initializer code has now run, printThree
prints 3
.
关于实例初始化程序代码被移入构造函数的过程中,您可能想知道:如果我有多个构造函数?代码移至哪一个?答案是,编译器将代码复制到每个构造函数中。 (您也可以在 javap -c
中看到它。)(如果您有一个非常复杂的实例初始化程序,那么如果编译器有效地将其转换为一个实例初始化程序,我不会感到惊讶。方法,但我没有看过。)
With regard to this instance initializer code getting moved into the constructor, you might be wondering: What if I have more than one constructor? Which one does the code get moved into? The answer is that the compiler duplicates the code into each constructor. (You can see that in javap -c
, too.) (If you have a really complicated instance initializer, I wouldn't be surprised if the compiler effectively turned it into a method, but I haven't looked.)
如果您确实调皮了一些,并在实例init期间调用了一个方法,这会更清楚一点:(实时复制)
It's a bit clearer if you do something really naughty and call a method during your instance init: (live copy)
class Super
{
public static void main (String[] args) {
new Sub();
}
Super() {
System.out.println("Super constructor");
this.printThree();
}
protected void printThree() {
System.out.println("Super's printThree");
}
}
class Sub extends Super
{
int three = this.initThree();
Sub() {
this.printThree();
}
private int initThree() {
System.out.println("Sub's initThree");
return 3;
}
protected void printThree() {
System.out.println("Sub's printThree: " + this.three);
}
}
输出:
Super constructor
Sub's printThree: 0
Sub's initThree
Sub's printThree: 3
注意, Sub's initThree按顺序出现。
Note where "Sub's initThree" came in that sequence.
这篇关于如果在构造函数中使用super调用重写的方法会发生什么的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!