2

我最近在一项潜在工作的测试中使用了以下代码。

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。我想知道的是为什么。

4

3 回答 3

3

在子类中调用ColorPoint超类的构造函数时,Point变量的值color尚未赋值。因此,当makeName()调用方法时,color实际上是null,因此name变量变为[4,2]:null,这就是您在打印时看到的内容。

于 2013-04-23T04:46:05.673 回答
3

观察创建新实例时发生的ColorPoint情况:

  • ColorPoint实例分配内存
  • x,yname设置为其默认值
  • ColorPoint构造函数被调用
  • 构造ColorPoint函数调用Point构造函数
  • Point构造函数分配给xy
  • Point构造函数调用makeName方法。
  • this.makeName解决为ColorPoint.makeName
  • ColorPoint.makeName来电Point.makeName
  • Point.makeName观察xy已设置,并按要求行事
  • ColorPoint.makeName观察colornull,并据此行事
  • Point构造函数赋值并name返回
  • ColorPoint构造函数赋值并color返回。糟糕,为时已晚。

关键字确保特定字段或变量将final被分配一次(编译器会这样做;仍然可以通过反射进行更改)。编译器还确保在写入之前不会读取局部变量。对于类字段,没有这样的先写后读规定。

这就是为什么,如前所述,您永远不应该调用可以从构造函数中覆盖的方法。

于 2013-04-23T05:01:12.170 回答
2

原因在代码中很明显。

ColorPoint makeName方法是从Point类的构造函数中调用的。此时private final variable color尚未初始化。

于 2013-04-23T04:53:44.757 回答