先上代码(adapted from Chapter 8, Thinking in Java, Fourth Edition):
class Glyph { void draw() { System.out.println("Glyph.draw()"); } Glyph() { System.out.println("Glyph constructor"); draw(); } } class RoundGlyph extends Glyph { private int radius = 1; RoundGlyph(int r) { System.out.println("before assignment in constructor, radius = " + radius); radius = r; System.out.println("RoundGlyph constructor, radius = " + radius); } void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius); } } public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); } } //Output: /* Glyph constructor RoundGlyph.draw(), radius = 0 before assignment in constructor, radius = 1 RoundGlyph constructor, radius = 5 */
根据[#0x0008],调用RoundGlyph的构造器时,会先调用Glyph的构造器。Glyph的构造器里调用了一个被覆写方法draw()。这里我们惊奇地发现:虽然RoundGlyph对象还没有创建完毕,但Glyph的构造器却实际调用了RoundGlyph的draw()方法(覆写方法),而且radius == 0(参JVM-Spec $2.17.6 Creation of New Class Instances 最后一段:
If methods are invoked that are overridden in subclasses in the object being initialized, then these overriding methods are used, even before the new object is completely created.)。
由此,我们可以对[#0x0008]做一些补充,即在调用ext class的constructor时,会有如下的过程:
->将分配给该ext class object的内存空间全部初始化为0x00(即用0x00填满该段内存空间);
->调用base class的constructor。如果base class的constructor有使用被覆写方法的话,则实际调用ext class中的覆写方法。由于上一个步骤的原因,此时ext class中各field均为0;
->base class的constructor调用完毕后后,开始初始化(包括默认初始化)ext class的member;
->调用ext class的constructor。
(2009年09月04日归纳:[#0x0023])