【问题标题】:Calling an overridden method from a constructor从构造函数调用重写的方法
【发布时间】:2011-12-09 18:39:23
【问题描述】:

在以下示例中:

class Base {    
    int  x=10;  

    Base() {    
      show();
    }  

    void show() {   
        System.out.print ("Base Show " +x + "  ");
    }  
}  

class Child extends Base {   
    int x=20;  

    Child() {
        show();
    }  

    void show() {    
        System.out.print("Child Show " + x +"  ") ; 
    }  

    public static void main( String s[ ] ) {   
        Base obj = new Child();   
    }  
} 
  • 为什么输出如下图所示
Child Show 0  Child Show 20
  • 我认为构造函数只有在其超级构造函数完成后才能访问实例成员。

我认为这里发生的事情是超级构造函数正在调用孩子的 show() 方法,因为该方法在 Child 中被覆盖。因为它已经被覆盖了,但是为什么 x 的值是 0,为什么它能够在超级构造函数完成之前访问这个方法?

【问题讨论】:

  • 在对象构造过程中是否启用了虚拟处理机制?我怀疑不是。
  • 在 C++ 中这可能会导致崩溃。
  • Effective Java 是一个很棒的 Java 资源,它非常详细地介绍了这一点。来自第 17 条:“构造函数不得直接或间接调用可覆盖的方法 (...) 如果覆盖方法依赖于子类构造函数执行的任何初始化,则该方法不会像预期的那样运行。...”如果您手头有这本书,我强烈建议您阅读此项目。

标签: java constructor


【解决方案1】:

我认为这里发生的事情是超级构造函数正在调用孩子的 show() 方法,因为这个方法在 Child 中被覆盖了。

没错

但是为什么x的值是0

因为它还没有初始化 (x of Child)

为什么它能够在超级构造函数完成之前访问这个方法?

这正是为什么在构造函数中永远不应该调用可以被覆盖的方法(非最终公共和受保护的)。

编辑:

这里奇怪的是所有东西都有默认/包私有可见性。这可能会产生一些奇怪的效果。见:http://www.cooljeff.co.uk/2009/05/03/the-subtleties-of-overriding-package-private-methods/

如果可能,我建议避免覆盖具有默认可见性的方法(您可以通过将它们声明为 final 来防止这种情况发生)。

【讨论】:

  • +1 顺序为 main -> Child() -> Base() -> Child.show() [x 尚未初始化] -> Base.show() [在 Base.x 之前= 20]
  • 不,顺序是 main -> Base() -> Child.show() [x 尚未初始化] -> Child() [Child.x = 20] -> Child.show( )
  • Object 类完成后,Child 类上的变量 x 是否已被赋予默认值 0?因为据我所知,这里的顺序是:new Child() -> Base() -> Object -> Child's implementation of show() ...
  • @anathema Object 类没有定义任何字段。但是 AFAIK,默认值是在内存分配期间设置的,所以类似于: main -> 使用默认值在堆上分配子内存 -> Object() -> Base() -> Child.show() [x 尚未初始化] -> Child() [Child.x = 20] -> Child.show()
【解决方案2】:

你可以从构造函数中调用被覆盖的方法,但它不好而且你不应该。您说明了这不好的原因:派生类没有机会初始化,因此将使用未初始化的字段-在您的示例中,int x 的默认值为0,这就是它打印@的原因987654323@.

【讨论】:

    【解决方案3】:

    构造函数链接 准确解释它是什么是有意义的。子类构造方法的首要任务是调用其超类的构造方法。这确保了子类对象的创建从继承链中它上面的类的初始化开始。

    http://java.about.com/b/2009/02/07/java-term-of-the-week-constructor-chaining.htm

    http://javahours.blogspot.com/2008/12/constructor-chain.html

    【讨论】:

      【解决方案4】:

      Childs 覆盖 show 方法被调用,因为这是 Java 规范所要求的。这是great discussion of why you should not do it。 x 的值为零,因为Child 还没有完成初始化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-10
        • 2014-02-16
        • 1970-01-01
        • 2020-07-28
        • 2016-05-31
        • 1970-01-01
        相关资源
        最近更新 更多