根据Java 泛型常见问题解答中的此条目 http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ302B,在某些情况下,泛型方法没有使用通配符类型的等效非泛型方法。根据那个答案,
如果方法签名使用多级通配符类型,则通用方法签名与其通配符版本之间始终存在差异。
他们给出了一个方法的例子<T> void print1( List <Box<T>> list)
,其中“需要相同类型的盒子列表”。通配符版本,void print2( List <Box<?>> list)
,“接受不同类型的盒子的异构列表”,因此不等效。
您如何解释以下两个方法签名之间的差异:
<T extends Iterable<?>> void f(Class<T> x) {}
void g(Class<? extends Iterable<?>> x) {}
直观上,这些定义似乎应该是等效的。然而,调用f(ArrayList.class)
使用第一种方法编译,但是调用g(ArrayList.class)
使用第二种方法会导致编译时错误:
g(java.lang.Class<? extends java.lang.Iterable<?>>) in Test
cannot be applied to (java.lang.Class<java.util.ArrayList>)
有趣的是,这两个函数都可以使用彼此的参数进行调用,因为以下代码可以编译:
class Test {
<T extends Iterable<?>> void f(Class<T> x) {
g(x);
}
void g(Class<? extends Iterable<?>> x) {
f(x);
}
}
Using javap -verbose Test
, 我理解了f()
具有通用签名
<T::Ljava/lang/Iterable<*>;>(Ljava/lang/Class<TT;>;)V;
and g()
具有通用签名
(Ljava/lang/Class<+Ljava/lang/Iterable<*>;>;)V;
如何解释这种行为?我应该如何解释这些方法签名之间的差异?