次のコードは、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);
^