14

このコードは、javac JDK バージョン 1.6.0_33-b03-424 を使用すると正常にコンパイルされますが、javac JDK バージョン 1.7.0_06 を使用するとコンパイルされません。

public class Test {
    private final int i = 0;

    void test(Object o) {
        if (getClass().isInstance(o)) {
            System.out.println(getClass().cast(o).i);
        }
    }
}

javac の出力は次のとおりです。

Test.java:6: error: i in Test is defined in an inaccessible class or interface
        System.out.println(getClass().cast(o).i);
                                             ^
1 error

結果を一時変数に格納するようにコードを変更するとgetClass.cast()、プログラムをエラーなしでコンパイルできます。

これは簡単に回避できますが、JLS 7 でのこの変更の根拠や、JDK 7 リリース ノートでのこのような変更についての言及を見つけることができません。ジェネリックへの型パラメーターのプライベート メンバーに関するアクセスの変更についての言及がありますが、ここでは当てはまりません。

これはjavacの回帰ですか? 以前は施行されていなかった制限が現在施行されていますか?

4

1 に答える 1

7

ええと、私はこれに困惑しています。私が冒険できる唯一の説明は、2 つのことの結合です。

1_getClass()ドキュメントには次のように書かれています。

実際の結果の型はClass<? extends |X|>、が呼び出さ|X|れた式の静的型の消去です。getClass

2_ Java 7 で導入された非互換性の 1 つは、型変数のプライベート メンバーへのアクセスをコンパイラが許可しなくなったことです。

そのため、コンパイラは、キャストが基本クラスまたはサブクラスに対して行われたかどうか確信が持てず、プライベート メンバーへのアクセスをブロックします。これは、キャストがサブクラスに割り当てられた場合、元の親クラスで定義されていたとしても違法になるためです。次の例に示すように:

class BaseTest {
    private final int i = 1;

    void test(Object o) {
        if (getClass().isInstance(o)) {                
            TestAccess to = TestAccess.class.cast(o);
            //System.out.println(to.i);  // ERROR: i has private access in BaseTest
        }
    }
}

class TestAccess extends BaseTest{}

したがって、より複雑な例ではより意味のある規則による Java の癖の 1 つだと思います。

于 2012-08-21T00:14:48.360 に答える