¿Cómo especifica JLS que los comodines no pueden usarse formalmente dentro de los métodos?
Siempre me he preguntado sobre algún aspecto extraño de los genéricos de Java y el uso de comodines. Digamos, tengo la siguiente API:
public interface X<E> {
E get();
E set(E e);
}
Y luego, digamos que declaramos los siguientes métodos:
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());
}
}
De mi comprensión "intuitiva",X<?>
es de hecho lo mismo queX<T>
, salvo que lo desconocido<T>
esformalmente desconocido para el código del cliente. Pero dentro defoo()
, Supongo que el compilador podría inferir (pseudo código JLS)<T0> := <?>[0], <T1> := <?>[1], etc...
. Esto es lo que hace la mayoría de los programadores de forma explícita e intuitiva. Ellos delegan a un método de ayuda privada, lo que lleva a un montón de código inútil de caldera:
public class Foo {
public void foo(X<?> x) {
foo0(x);
}
private <T> void foo0(X<T> x) {
x.set(x.get());
}
}
Otro ejemplo:
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());
}
}
En otras palabras, el compilador sabe que el comodín enx.set()
es formalmente el mismo que el comodín enx.get()
. ¿Por qué no puede usar esa información? ¿Hay un aspecto formal en elJLS, eso explica esta falta de compilador "característica"?