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