【问题标题】:What is the order of the Constructors in this Java Code?此 Java 代码中构造函数的顺序是什么?
【发布时间】:2012-03-28 09:43:28
【问题描述】:

代码如下,我定义了父子两个类,并在主函数中创建:

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

但我不明白这是怎么发生的?谁能告诉我为什么?

【问题讨论】:

  • 经验教训:不要从可以被覆盖的构造函数中调用方法。
  • 另一个要吸取的教训是,您应该始终尝试提出不能被误解的“调试”消息:我会将您的方法更改为 System.out.println("Son.who()");System.out.println("Son.tell(" + name + ")"); , System.out.println("Father.who()");System.out.println("Father.tell(" + name + ")");

标签: java


【解决方案1】:
  1. 让我们从Son的构造函数开始。

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

    public Father() {
        who();
        tell(name);
    }
    
  3. 因为who()Son 覆盖,Son 的版本将被调用,打印“this is son”。

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

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

【讨论】:

    【解决方案2】:

    这就是所谓的:

    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"   
    

    经验教训:

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

        Father()的构造函数内部的who()调用覆盖方法。

        【讨论】:

          【解决方案5】:

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

          发生的情况是:没有父亲实例,只有一个儿子实例。 (不过,它与父亲的赋值兼容。)

          Son 构造函数调用Father 构造函数。后者调用覆盖的 (!) 方法,因此从未调用过 Father.who 和 Father.tell!在 Son 构造函数完成之前(!)调用了被覆盖的方法。

          我的建议:

          1. 如果在构造函数中调用方法,请将其设为最终方法。或者让整个班级决赛。或者至少将被调用的方法设为私有。
          2. 永远不要覆盖在构造函数中调用的方法。
          3. 如果您必须违反上述建议,请撰写大量的 cmets,说明您这样做的原因以及您预期会发生什么。编写单元测试以确保您的假设有效。

          【讨论】:

            猜你喜欢
            • 2023-03-31
            • 1970-01-01
            • 2010-10-13
            • 1970-01-01
            • 1970-01-01
            • 2016-11-20
            • 1970-01-01
            • 2017-12-05
            • 1970-01-01
            相关资源
            最近更新 更多