类A
在构造函数中调用公共方法f()
。 B类使用自己的实现覆盖方法f()
。
假设您实例化对象B
..对象f()
的方法B
将在对象A
的构造函数中调用,尽管对象B
不是完全初始化。
任何人都可以解释这种行为吗?
编辑: 是的,不推荐练习..但我不明白为什么 Java没有调用{{1}实现基类f()
而不是“伸出”到派生类A
的{{1}}实现。
代码:
f()
输出:
B
答案 0 :(得分:8)
你是对的,这就是它的工作方式。但是不建议这样做,因为从你的班级继承的人可能会无意中破坏它。
答案 1 :(得分:4)
每当您创建子类的实例时,首先调用超类构造函数(隐式super()
)。所以打印
a: constructor
接下来调用 f()
,并且由于子类重写了超类方法,因此调用子类f()
。所以你会看到
B: f()
现在,子类尚未初始化(仍然是super()正在执行)所以x
默认为值0
,因为这是类型{的默认值{1}}。因为您将其递增(int
),它变为this.x++;
1
现在,超类构造函数已完成,并在子类构造函数中恢复,因此
B: x = 1
现在,实例变量已设置为您指定的值(对应于类型的默认值(数字为B: constructor
,0
为false
和boolean
参考))
注意:如果您现在在新创建的对象上打印null
的值,它将为x
由于这是一种不好的做法,静态代码分析工具(PMD,FIndBugs等)会在您尝试执行此操作时向您发出警告。
答案 2 :(得分:0)
我只是提供一个链接,因为我对这个问题的了解不多。有关构造函数调用顺序的教程,请参阅here。
页面末尾与您描述的情况相关的最突出的引用如下:
- 调用基类构造函数。递归地重复该步骤,以便首先构造层次结构的根, 然后是下一个派生类等,直到派生最多的类 到达了。
- 成员初始化程序按声明顺序调用。派生类构造函数的主体被调用。
醇>
因此,正如您在示例中所示,初始化了基类,然后对每个以下类进行了实例化,最后初始化了成员变量。
但正如比尔所说,这不是一个好习惯。跟着比尔说的话。他的代表人数比我多。
编辑:有关更完整的答案,请参阅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()。
但正如其他人评论的那样,这不是一个好习惯。