构造函数中的多态方法(Java)
A类在构造函数中调用公共方法f()
。 B类用自己的实现覆盖方法f()
。
假设您实例化对象B
..对象B
方法f()
将在对象A
的构造函数中调用,尽管对象B
未完全初始化。
谁能解释这种行为?
编辑:是的,它不推荐练习..但我不明白为什么 Java没有调用基类A
的f()
实现而不是“伸出”到派生类B
的f()
实现。
码:
class A { A() { System.out.println("A: constructor"); f(); } public void f() { System.out.println("A: f()"); } } class B extends A { int x = 10; B() { System.out.println("B: constructor"); } @Override public void f() { System.out.println("B: f()"); this.x++; System.out.println("B: x = " + x); } } public class PolyMethodConst { public static void main(String[] args) { new B(); } }
输出:
A: constructor B: f() B: x = 1 B: constructor
你是对的,这是它的工作方式。 但是不建议这样做,因为从你的class级inheritance的人可能会无意中破坏它。
每当您创建子类的实例时,首先调用超类构造函数(隐式super()
)。 所以它打印
a: constructor
接下来调用f()
,因为子类重写了超类方法,所以调用子类f()
。 所以你会看到
B: f()
现在,子类尚未初始化(仍然是super()正在执行)所以x
default是值0
因为这是int
类型的默认值。 因为你增加它( this.x++;
)它变成1
B: x = 1
现在,超类构造函数已完成,并在子类构造函数中恢复,因此
B: constructor
实例变量现在设置为您指定的值(对应于与类型对应的默认值( 0
表示数字, 0
表示boolean
, null
表示引用))
注意:如果现在在新创建的对象上打印x
的值,它将为10
由于这是一种不好的做法,静态代码分析工具(PMD,FIndBugs等)会在您尝试执行此操作时向您发出警告。
我只是提供一个链接,因为我对这个问题的了解不多。 请参阅此处获取有关构造函数调用顺序的教程。
页面末尾与您描述的情况相关的最突出的引用如下:
- 调用基类构造函数。 递归地重复该步骤,使得首先构造层次结构的根,然后是下一个派生类等,直到到达最派生的类。
- 成员初始化程序按声明顺序调用。 调用派生类构造函数的主体。
因此,正如您在示例中所示,初始化了基类,然后对每个以下类进行了实例化,最后初始化了成员变量。
但正如比尔所提到的,这不是一个好习惯。 按照比尔说的那样。 他的代表人数比我多。
编辑 :有关更完整的答案,请参阅Jon Skeet的回答 。 此答案中的链接已断开, 只能找到JLS的pdf副本AFAIK 。 以下是.pdf格式的JLS副本。 相关章节是第8.8.7.1节。 有一个解释说明构造函数调用顺序在该答案中。
当new B()
,A的构造函数被隐式调用或通过super()
调用。 虽然它是在A类中定义的,但实际上当前的类是B.
尝试将以下调试信息添加到A
的构造函数和函数中。
System.out.println(this.getClass());
在你的情况下,类A中的函数f()已被类B重写,因此A()中的函数将调用B()的实现。 但是,如果f()是私有方法并且不能被B覆盖,则将以更高的优先级调用Af()。
但正如其他人评论的那样,这不是一个好习惯。