下面這個程序有兩個不可變的值類(value class),值類即其實例表示值的類。第一個類用整數(shù)坐標來表示平面上的一個點,第二個類在此基礎(chǔ)上添加了一點顏色。主程序?qū)?chuàng)建和打印第二個類的一個實例。那么,下面的程序?qū)⒋蛴〕鍪裁茨兀?BR> 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();
}
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);
this.color = color;
}
protected String makeName() {
return super.makeName() + ":" + color;
}
public static void main(String[] args) {
System.out.println(new ColorPoint(4, 2, "purple"));
}
}
main方法創(chuàng)建并打印了一個ColorPoint實例。println方法調(diào)用了該ColorPoint實例的toString方法,這個方法是在Point中定義的。toString方法將直接返回name域的值,這個值是通過調(diào)用makeName方法在Point的構(gòu)造器中被初始化的。對于一個Point實例來說,makeName方法將返回[x,y]形式的字符串。對于一個ColorPoint實例來說,makeName方法被覆寫為返回[x,y]:color形式的字符串。在本例中,x是4,y是2,color的purple,因此程序?qū)⒋蛴4,2]:purple,對嗎?不,如果你運行該程序,就會發(fā)現(xiàn)它打印的是[4,2]:null。這個程序出什么問題了呢?
這個程序遭遇了實例初始化順序這一問題。要理解該程序,我們就需要詳細跟蹤該程序的執(zhí)行過程。下面是該程序注釋過的版本的列表,用來引導我們了解其執(zhí)行順序:
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 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();
}
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);
this.color = color;
}
protected String makeName() {
return super.makeName() + ":" + color;
}
public static void main(String[] args) {
System.out.println(new ColorPoint(4, 2, "purple"));
}
}
main方法創(chuàng)建并打印了一個ColorPoint實例。println方法調(diào)用了該ColorPoint實例的toString方法,這個方法是在Point中定義的。toString方法將直接返回name域的值,這個值是通過調(diào)用makeName方法在Point的構(gòu)造器中被初始化的。對于一個Point實例來說,makeName方法將返回[x,y]形式的字符串。對于一個ColorPoint實例來說,makeName方法被覆寫為返回[x,y]:color形式的字符串。在本例中,x是4,y是2,color的purple,因此程序?qū)⒋蛴4,2]:purple,對嗎?不,如果你運行該程序,就會發(fā)現(xiàn)它打印的是[4,2]:null。這個程序出什么問題了呢?
這個程序遭遇了實例初始化順序這一問題。要理解該程序,我們就需要詳細跟蹤該程序的執(zhí)行過程。下面是該程序注釋過的版本的列表,用來引導我們了解其執(zhí)行順序:
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
}