Następujący kod kompiluje dobrze w Javie 1.6, ale nie kompiluje się w Javie 1.7. Czemu?Dlaczego ten kod kompiluje się w Javie 1.6, ale nie w Javie 1.7?
Odpowiednią częścią kodu jest odniesienie do prywatnego pola danych. Odniesienie pochodzi z tej samej klasy, w której pole jest zdefiniowane, a więc wydaje się legalne. Ale dzieje się to za pośrednictwem zmiennej generowanej maszynowo. Ten kod - uproszczony przykład oparty na klasie z wewnętrznej biblioteki - działał w Javie 1.6, ale nie w Javie 1.7.
Nie pytam, jak to obejść. Już to zrobiłem. Próbuję znaleźć wyjaśnienie, dlaczego to już nie działa. Trzy możliwości przyjść do głowy:
- Ten kod jest NIE PRAWNA według JLS i nigdy nie powinny być zestawiane (był to błąd w 1,6 kompilatora, utrwalano w 1,7)
- Ten kod jest PRAWNA według JLS i należy opracować (wsteczną kompatybilność błąd został wprowadzony do 1,7 kompilator)
- Kod ten spada do szary obszar w JLS
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;
}
}
wyjście Compiler:
> 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
Uzupełnienie. Ten sam problem występuje, jeśli odwołanie odnosi się do metody prywatnej zamiast do prywatnej zmiennej członkowskiej. Działa to w Javie 1.6, ale nie w 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;
}
}
wyjście Compiler:
> 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);
^
Sugerowałbym dekompilację obu wygenerowanych plików klas, wtedy różnica powinna być oczywista. – Landei
@Landei Nie ma wygenerowanego pliku klasy w przypadku 1.7, ponieważ kompilator odmawia skompilowania go. –