他们举了一个例子,一个方法如果一个方法签名使用多级通配符类型,那么泛型方法签名和它的通配符版本之间总是存在差异。
<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);
}
}
使用
javap -verbose Test
命令,可以看到 f()
的通用签名。<T::Ljava/lang/Iterable<*>;>(Ljava/lang/Class<TT;>;)V;
而 g()
具有通用签名
(Ljava/lang/Class<+Ljava/lang/Iterable<*>;>;)V;
这种行为是什么原因?我应该如何解释这些方法签名之间的差异?
g
的Iterable
中移除通配符确实可以编译通过:void g(Class<? extends Iterable> x)
。 - cklab