Der folgende Code wird in Java 1.6 kompiliert, kann jedoch nicht in Java 1.7 kompiliert werden. Warum?Warum kompiliert dieser Code in Java 1.6, aber nicht in Java 1.7?
Der relevante Teil des Codes ist der Verweis auf das private Feld 'data'. Die Referenz stammt aus derselben Klasse, in der das Feld definiert ist, und scheint daher legal zu sein. Aber es geschieht über eine generisch typisierte Variable. Dieser Code - ein abgespecktes Beispiel, basierend auf einer Klasse aus einer internen Bibliothek - arbeitete in Java 1.6, jetzt aber nicht in Java 1.7.
Ich frage nicht, wie man das umgeht. Das habe ich schon gemacht. Ich versuche eine Erklärung dafür zu finden, warum das nicht mehr funktioniert. Drei Möglichkeiten in den Sinn kommen:
- Dieser Code ist NICHT RECHTS zum JLS nach und hätte nie zusammengestellt (es war ein Fehler in der 1,6-Compiler, fest in 1.7)
- Dieser Code ist LEGAL gemäß der JLS und sollte kompilieren (a Rückwärtskompatibilität Fehler wurde in die 1,7-Compiler eingeführt)
- Dieser Code fällt in einen GRAY AREA im JLS
:
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;
}
}
Compiler Ausgang:
> 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
Addendum. Das gleiche Problem tritt auf, wenn der Verweis auf eine private Methode statt auf eine private Membervariable erfolgt. Dies funktioniert in Java 1.6, aber nicht in 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;
}
}
Compiler Ausgabe:
> 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);
^
Ich würde vorschlagen, beide generierten Klassendateien zu dekompilieren, dann sollte der Unterschied offensichtlich sein. – Landei
@Landei Es gibt keine generierte Klassendatei im Fall 1.7, da der Compiler es nicht kompiliert. –