本Java代码中构造函数的顺序是什么?

时间:2012-03-28 09:43:29

标签: java

这是代码,我定义了两个名为Father和Son的类,并在main函数中创建它们:

public class Test {
    public static void main(String[] args) {
        Father father = new Son();
    }
}

class Father {
    private String name = "father";
    public Father() {
        who();
        tell(name);
    }
    public void who() {
        System.out.println("this is father");
    }
    public void tell(String name) {
        System.out.println("this is " + name);
    }
}

class Son extends Father {
    private String name = "son";
    public Son() {
        who();
        tell(name);
    }
    public void who() {
        System.out.println("this is son");
    }
    public void tell(String name) {
        System.out.println("this is " + name);
    }
}

我得到了这样的输出:

this is son
this is father
this is son
this is son

但我无法理解这是怎么发生的?任何人都可以告诉我为什么?

5 个答案:

答案 0 :(得分:9)

  1. 让我们从Son的构造函数开始。

    public Son() {
        super(); // implied
        who();
        tell(name);
    }
    
  2. 调用父的构造函数。

    public Father() {
        who();
        tell(name);
    }
    
  3. 由于who()会覆盖Son,因此会调用Son的版本,打印“这是儿子”。

  4. tell()也被覆盖,但传入的值为Father.name,打印“这是父亲”。

  5. 最后,who()的构造函数中的tell(name)Son调用将分别打印“this is son”和“this is son”。

答案 1 :(得分:6)

以下是所谓的:

new Son()
=>  
  Son._init
   =>  first every constructor calls super()
      Father._init
         Object._init
         who()  => is overridden, so prints "son"
         tell(name) => name is private, so cannot be overridden => "father"
   who()  => "son"
   tell(name)  => "son"   

要学习的经验教训:

  • 私有字段和方法是私有的。不能被覆盖。
  • 不要从可以被覆盖的构造函数中调用方法。这可以在半初始化的类状态上调用方法(但在你的情况下不会发生)。

答案 2 :(得分:3)

当您创建Son实例时,将调用父类的构造函数(即Father());这里调用了who()方法,但它是你在Son中声明的重写版本,所以这是你的第一行(其中String在方法中被硬编码)。

第二行来自tell(name)Father(),其中tell()被覆盖但name == "father"因为调用来自Father的构造函数, nameprivate类的Father字段。

控制返回Son()构造函数,最后两行直接来自Son类构造函数。

答案 3 :(得分:2)

Father()之前调用

Son()。隐式调用超类默认构造函数,我们这里不需要super()语句。

who()的构造函数中的Father()调用重写方法。

答案 4 :(得分:0)

上面的代码特别是Bad Style(TM)。 ; - )

会发生什么:没有父实例,只有Son实例。 (然而,它与父亲的任务兼容。)

Son构造函数调用父构造函数。后者调用重写的(!)方法,因此永远不会调用Father.who和Father.tell!在子构造函数完成之前(!)调用重写的方法。

我的建议:

  1. 如果在构造函数中调用方法,请将其设为final。或者让全班决赛。或者至少将被调用的方法设为私有。
  2. 永远不要覆盖构造函数中调用的方法。
  3. 如果您不得不违反上述建议,请写下有关您为什么这样做以及您希望发生什么的广泛评论。编写单元测试以确保您的假设有效。