您所做的假设与实际情况相反:
Iterable<? extends iface_classB> getThings();
意味着getThings()
返回至少具有iface_classB
. 因此,您不能将结果分配getThings()
给 any Iterable< impl_of_iface_classB >
,因为您只能确定对象公开了 a 的功能iface_classB
。
例如,如果返回的对象getThings()
实际上是一个Iterable<impl2_of_iface_classB>
,在哪里impl2_of_iface_classB
扩展iface_classB
?可迭代对象不具备impl_of_iface_classB
对象的功能。
在实践中,如果B1
和B2
派生自B
,则完全允许有
A<? extends B> x;
A<B1> y;
A<B2> z;
x = y;
x = z;
因此getThings()
不能依赖泛型参数所代表的含义:它只能作为“普通”使用iface_classB
。
更重要的是,您希望能够分配给Iterable<iface_classB>
,但您不能(除非您执行未经检查的强制转换,否则不会)。这是因为通配符本质上意味着“一组可行的通用参数”。想象一下,您将通配符替换为您使用的具体泛型参数:如果参数不匹配,由于类型不兼容,您会得到通常的编译时错误。编译器必须考虑所有情况,不允许您这样做。所以,
A<? extends B> x;
A<B> y = x;
虽然实际上是安全的,但不允许这样做,因为x
可能会分配一个不同于 的参数B
,从而为分配的两侧产生不同的类型。相反,
A<B> x;
A<? extends B> y = x;
是允许的,因为 的类型y
代表一组备选方案,并且该组包括A<B>
. 一旦y
像上面这样分配,集合的具体估值就被实际选择了。