如果在构造函数中使用super调用重写的方法会发生什么 [英] What happens if you call an overridden method using super in a constructor

查看:76
本文介绍了如果在构造函数中使用super调用重写的方法会发生什么的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有两个类 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:


  1. 默认的超级构造函数调用,以及

  1. 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:


  1. JVM会创建实例并将所有实例字段设置为默认值(所有位)关闭)。因此,此时,三个字段存在,并且值<< c $ c> 0 。

JVM调用 Sub1

Sub1 立即调用 super() Super1 ),这会... / p>

Sub1 immediately calls super() (Super1), which...


  1. ...调用 printThree 。由于 printThree 被覆盖,即使对它的调用在 Super1 的代码中,也被覆盖方法( Sub1 中的一个)被调用。这是Java实现多态的一部分。由于三个的实例初始化器尚未运行,因此三个包含 0 ,这就是输出。

  1. ...calls printThree. Since printThree is overridden, even though the call to it is in the code for Super1, it's the overridden method (the one in Sub1) that gets called. This is part of how Java implements polymorphism. Since three's instance initializer hasn't been run yet, three contains 0, 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屋!

  • 查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆