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新しいインスタンスを作成するとどうなるかを観察します。

  • ColorPointインスタンスにメモリが割り当てられている
  • xyおよびnameデフォルト値に設定されています
  • 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キーワードは、特定のフィールドまたは変数が 1 回だけ割り当てられることを保証します (コンパイラーがそれを行います。リフレクションを介して変更することは可能です)。コンパイラは、ローカル変数が書き込まれる前に読み込まれないことも保証します。クラスフィールドには、読み取り前に書き込みを行うという規定はありません。

そのため、前述のように、コンストラクターからオーバーライドできるメソッドを呼び出すべきではありません。

于 2013-04-23T05:01:12.170 に答える
3

ColorPointスーパークラスのコンストラクターが呼び出されたときのサブクラスでPointは、変数への値colorはまだ代入されていません。したがって、makeName()メソッドが呼び出されると、color実際nullには になるため、name変数は になり[4,2]:null、印刷するとそれが表示されます。

于 2013-04-23T04:46:05.673 に答える
2

理由はコードで明らかです。

ColorPoint makeNameメソッドは、クラスのコンストラクターから呼び出されますPoint。その時点では、private final variable colorは初期化されていません。

于 2013-04-23T04:53:44.757 に答える