您所做的假设与实际情况相反:
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像上面这样分配,集合的具体估值就被实际选择了。