Wie legt das JLS fest, dass Platzhalter in Methoden nicht formal verwendet werden können?
Ich habe mich immer über einen seltsamen Aspekt von Java-Generika und die Verwendung von Platzhaltern gewundert. Angenommen, ich habe die folgende API:
public interface X<E> {
E get();
E set(E e);
}
Nehmen wir an, wir deklarieren die folgenden Methoden:
public class Foo {
public void foo(X<?> x) {
// This does not compile:
x.set(x.get());
}
public <T> void bar(X<T> x) {
// This compiles:
x.set(x.get());
}
}
Nach meinem "intuitiven" VerständnisX<?>
ist in der Tat das gleiche wieX<T>
, außer dass der Unbekannte<T>
istformal Clientcode unbekannt. Aber innerhalb vonfoo()
, Ich würde vermuten, dass der Compiler darauf schließen könnte (Pseudo-JLS-Code)<T0> := <?>[0], <T1> := <?>[1], etc...
. Dies ist, was die meisten Programmierer explizit und intuitiv tun. Sie delegieren an eine private Helfer-Methode, die zu einer Menge nutzlosem Code auf der Kesselplatte führt:
public class Foo {
public void foo(X<?> x) {
foo0(x);
}
private <T> void foo0(X<T> x) {
x.set(x.get());
}
}
Ein anderes Beispiel:
public class Foo {
public void foo() {
// Assuming I could instanciate X
X<?> x = new X<Object>();
// Here, I cannot simply add a generic type to foo():
// I have no choice but to introduce a useless foo0() helper method
x.set(x.get());
}
}
Mit anderen Worten, der Compiler weiß, dass der Platzhalter inx.set()
ist formal das Gleiche wie der Platzhalter inx.get()
. Warum kann es diese Informationen nicht verwenden? Gibt es einen formalen Aspekt in derJLS, das erklärt dieses fehlende Compiler "Feature"?