我最近在测试潜在工作时有以下代码。
class Point {
protected final int x, y;
private final String name;
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"));
}
}
测试询问程序员打算打印出来的是什么,[4,2]:紫色。它还询问了实际打印出来的内容,即[4:2]:null。我想知道的是为什么。
答案 0 :(得分:3)
在子类ColorPoint
中,当调用超类Point
的构造函数时,尚未分配变量color
的值。因此,当调用makeName()
方法时,color
实际上是null
,因此name
变量变为[4,2]:null
,这就是您在打印时看到的内容。
答案 1 :(得分:3)
观察创建新ColorPoint
实例时会发生什么:
ColorPoint
实例x
,y
和name
设置为默认值ColorPoint
构造函数被称为ColorPoint
构造函数调用Point
构造函数Point
构造函数分配给x
和y
Point
构造函数调用makeName
方法。this.makeName
解析为ColorPoint.makeName
ColorPoint.makeName
来电Point.makeName
Point.makeName
观察x
和y
已设置,并根据需要发挥作用ColorPoint.makeName
观察color
为null
,并采取相应行动Point
构造函数分配给name
并返回ColorPoint
构造函数分配给color
并返回。哎呀,太晚了。 final
关键字确保将特定字段或变量分配给一次(编译器会这样做;它仍然可以通过反射进行更改)。编译器还确保在写入本地变量之前不会读取它。在读取类字段之前,没有这样的写入规定。
这就是为什么,如前所述,你永远不应该调用可以从构造函数中覆盖的方法。
答案 2 :(得分:2)
原因在代码中很明显。
从ColorPoint
类的构造函数调用makeName
Point
方法。此时private final variable color
尚未初始化。