千万不要在构造器中调用可覆盖的方法。
package ch6_classy_puzzlers.puzzle_51;
class Point {
protected final int x, y;
private final String name; // Cached at construction time
Point(int x, int y) {
this.x = x;
this.y = y;
name = makeName();//(3) Invoke subclass method
}
protected String makeName() {
return "[" + x + "," + y + "]";
}
public final String toString() {
return name;
}
}
public class ColorPoint extends Point {
private final String color;
ColorPoint(int x, int y, String color) {
super(x, y);//(2) Chain to Point Constructor
this.color = color;//(5) Initialize blank final- Too late
}
protected String makeName() {
// (4) Executes before subclass constructor body!
return super.makeName() + ":" + color;
}
public static void main(String[] args) {
//(1) Invoke subclass constructor
System.out.println(new ColorPoint(4, 2, "purple"));
}
}
它的输出为[4,2]:null,请看注释里的语句执行顺序。其实我们可以将其Point类的中的Point构造函数移除对name的初始化,并写一个final synchronized String toString方法,tostring里面如果name为空,则对其初始化。