构造函数中的多态方法(Java)

时间:2012-02-03 02:02:24

标签: java inheritance constructor polymorphism override

A在构造函数中调用公共方法f()。 B类使用自己的实现覆盖方法f()

假设您实例化对象B ..对象f()的方法B将在对象A的构造函数中调用,尽管对象B不是完全初始化。

任何人都可以解释这种行为吗?

编辑: 是的,不推荐练习..但我不明白为什么 Java没有调用{{1}实现基类f()而不是“伸出”到派生类A的{​​{1}}实现。

代码:

f()

输出:

B

4 个答案:

答案 0 :(得分:8)

你是对的,这就是它的工作方式。但是不建议这样做,因为从你的班级继承的人可能会无意中破坏它。

答案 1 :(得分:4)

每当您创建子类的实例时,首先调用超类构造函数(隐式super())。所以打印

a: constructor
接下来调用

f(),并且由于子类重写了超类方法,因此调用子类f()。所以你会看到

B: f()

现在,子类尚未初始化(仍然是super()正在执行)所以x默认为值0,因为这是类型{的默认值{1}}。因为您将其递增(int),它变为this.x++;

1

现在,超类构造函数已完成,并在子类构造函数中恢复,因此

B: x = 1

现在,实例变量已设置为您指定的值(对应于类型的默认值(数字为B: constructor 0falseboolean参考))

注意:如果您现在在新创建的对象上打印null的值,它将为x

由于这是一种不好的做法,静态代码分析工具(PMD,FIndBugs等)会在您尝试执行此操作时向您发出警告。

答案 2 :(得分:0)

我只是提供一个链接,因为我对这个问题的了解不多。有关构造函数调用顺序的教程,请参阅here

页面末尾与您描述的情况相关的最突出的引用如下:

  
      
  1. 调用基类构造函数。递归地重复该步骤,以便首先构造层次结构的根,   然后是下一个派生类等,直到派生最多的类   到达了。
  2.   
  3. 成员初始化程序按声明顺序调用。派生类构造函数的主体被调用。
  4.   

因此,正如您在示例中所示,初始化了基类,然后对每个以下类进行了实例化,最后初始化了成员变量。

但正如比尔所说,这不是一个好习惯。跟着比尔说的话。他的代表人数比我多。

编辑:有关更完整的答案,请参阅this Jon Skeet answer。此答案中的链接已断开,只能找到JLS的pdf副本AFAIK Here是.pdf格式的JLS副本。相关章节是第8.8.7.1节。可以解释构造函数调用顺序在该答案中的作用。

答案 3 :(得分:0)

new B()时,隐式调用A的构造函数或通过super()调用。虽然它是在A类中定义的,但实际上当前的类是B。

尝试将以下调试信息添加到A的构造函数和函数中。

System.out.println(this.getClass());

在你的情况下,A类中的函数f()已被B类覆盖,因此A()中的函数将调用B()的实现。但是,如果f()是私有方法并且不能被B覆盖,则将以更高的优先级调用A.f()。

但正如其他人评论的那样,这不是一个好习惯。