我一直想知道 Java 泛型的一些奇怪方面以及通配符的使用。假设,我有以下 API:
public interface X<E> {
E get();
E set(E e);
}
然后,假设我们声明了以下方法:
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());
}
}
根据我的“直觉”理解,X<?>
实际上与 相同X<T>
,只是未知对于客户端代码<T>
来说是形式上未知的。但是在里面foo()
,我猜编译器可以推断(伪 JLS 代码)<T0> := <?>[0], <T1> := <?>[1], etc...
。这是大多数程序员明确而直观地做的事情。他们委托给一个私有的辅助方法,这导致了很多无用的样板代码:
public class Foo {
public void foo(X<?> x) {
foo0(x);
}
private <T> void foo0(X<T> x) {
x.set(x.get());
}
}
另一个例子:
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());
}
}
换句话说,编译器知道通配符 inx.set()
形式上与通配符 in 相同x.get()
。为什么它不能使用这些信息?JLS中是否有一个正式的方面来解释这个缺乏编译器的“功能”?