16

次のコードは、Java 1.6 では正常にコンパイルされますが、Java 1.7 ではコンパイルに失敗します。なんで?

コードの関連部分は、プライベート「データ」フィールドへの参照です。参照は、フィールドが定義されているのと同じクラス内からのものであるため、正当なようです。しかし、それはジェネリック型変数を介して発生しています。このコード (社内ライブラリのクラスに基づいて簡略化された例) は、Java 1.6 では機能しましたが、Java 1.7 では機能しません。

これを回避する方法を尋ねているわけではありません。私はすでにそれをしました。これが機能しなくなった理由の説明を見つけようとしています。次の 3 つの可能性が考えられます。

  • このコードはJLS によれば合法ではなく、決してコンパイルすべきではありません (1.6 コンパイラにバグがあり、1.7 で修正されました)。
  • このコードはJLSによれば合法であり、コンパイルする必要があります (1.7 コンパイラには下位互換性のバグが導入されています)。
  • このコードは JLSのGRAY AREAに分類されます

Foo.java:

import java.util.TreeMap;
import java.util.Map;

public abstract class Foo<V extends Foo<V>> {

    private final Map<String,Object> data = new TreeMap<String,Object>();

    protected Foo() { ; }

    // Subclasses should implement this as 'return this;'
    public abstract V getThis();

    // Subclasses should implement this as 'return new SubclassOfFoo();'
    public abstract V getEmpty();

    // ... more methods here ...

    public V copy() {
        V x = getEmpty();
        x.data.clear();      // Won't compile in Java 1.7
        x.data.putAll(data); // "
        return x;
    }

}

コンパイラ出力:

> c:\tools\jdk1.6.0_11\bin\javac -version
javac 1.6.0_11

> c:\tools\jdk1.6.0_11\bin\javac c:\temp\Foo.java

> c:\tools\jdk1.7.0_10\bin\javac -version
javac 1.7.0_10

> c:\tools\jdk1.7.0_10\bin\javac c:\temp\Foo.java
Foo.java:18: error: data has private access in Foo
        x.data.clear();
         ^
Foo.java:19: error: data has private access in Foo
        x.data.putAll(data);
         ^
2 errors

補遺。参照がプライベート メンバ変数ではなくプライベート メソッドである場合も、同じ問題が発生します。これは Java 1.6 では機能しますが、1.7 では機能しません。

Foo2.java:

import java.util.TreeMap;
import java.util.Map;

public abstract class Foo2<V extends Foo2<V>> {

    private final Map<String,Object> data = new TreeMap<String,Object>();

    protected Foo2() { ; }

    // Subclasses should implement this as 'return this;'
    public abstract V getThis();

    // Subclasses should implement this as 'return new SubclassOfFoo();'
    public abstract V getEmpty();

    // ... more methods here ...

    public V copy() {
        V x = getEmpty();
        x.theData().clear();      // Won't compile in Java 1.7
        x.theData().putAll(data); // "
        return x;
    }

    private Map<String,Object> theData() {
        return data;
    }

}

コンパイラ出力:

> c:\tools\jdk1.6.0_11\bin\javac c:\temp\Foo2.java

> c:\tools\jdk1.7.0_10\bin\javac c:\temp\Foo2.java
Foo2.java:18: error: theData() has private access in Foo2
        x.theData().clear();
         ^
Foo2.java:19: error: theData() has private access in Foo2
        x.theData().putAll(data);
         ^
4

1 に答える 1