设计构建器时一个特别有效的规则:用尽可能简单的方法使对象进入就绪状态;如果可能避免调用任何其他方法,在构建器中唯一能安全调用的就是在基础类中具有final属性的那些方法,(也可以是被private 修饰的方法,因为被private修饰的方法自动具有final的属性),这些方法不能被覆盖,所以不会出现下面的情况.
abstract class Glyph { abstract void draw(); Glyph() { System.out.println("Glyph() before draw()"); draw(); System.out.println("Glyph() after draw()"); } } class RoundGlyph extends Glyph { int radius = 1; RoundGlyph(int r) { radius = r; System.out.println( "RoundGlyph.RoundGlyph(), radius = " + radius); } void draw() { System.out.println( "RoundGlyph.draw(), radius = " + radius); } } public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); } }在Glyph 中,draw()方法是“抽象的”(abstract),所以它可以被其他方法覆盖。事实上,我们在 RoundGlyph中不得不对其进行覆盖。但 Glyph构建器会调用这个方法,而且调用会在RoundGlyph.draw()中 止,这看起来似乎是有意的。但请看看输出结果: Glyph() before draw() RoundGlyph.draw(), radius = 0 Glyph() after draw() RoundGlyph.RoundGlyph(), radius = 5 当Glyph 的构建器调用 draw()时,radius 的值甚至不是默认的初始值1,而是 0。这可能是由于一个点号或 者屏幕上根本什么都没有画而造成的。这样就不得不开始查找程序中的错误,试着找出程序不能工作的原 因。 前一节讲述的初始化顺序并不十分完整,而那是解决问题的关键所在。初始化的实际过程是这样的: (1) 在采取其他任何操作之前,为对象分配的存储空间初始化成二进制零。 (2) 就象前面叙述的那样,调用基础类构建器。此时,被覆盖的draw()方法会得到调用(的确是在 RoundGlyph构建器调用之前),此时会发现 radius的值为 0,这是由于步骤(1)造成的。 (3) 按照原先声明的顺序调用成员初始化代码。 (4) 调用衍生类构建器的主体。