为什么
List<?> list = new ArrayList<Object>();
同时
List<Box<?>> boxList = new ArrayList<Box<Object>>();
是不允许的
List<? extends Box<?>>
的含义也是如此。
答案 0 :(得分:2)
因为List<Box<?>>
接受包含任何内容的框。因此以下是有效的:
List<Box<?>> boxes = new ArrayList<>();
boxes.add(new Box<Integer>());
boxes.add(new Box<String>());
List<Box<Object>>
只接受Box<Object>
的实例。因此,以下内容无效,因为Box<Integer>
和Box<String>
不是Box<Object>
。
List<Box<Object>> boxes = new ArrayList<>();
boxes.add(new Box<Integer>());
boxes.add(new Box<String>());
现在,如果你的问题是&#34;为什么Box<String>
不是Box<Object>
&#34;答案是,如果是,你可以做以下事情,这会破坏泛型类型的类型安全性:
Box<Integer> boxOfIntegers = new Box<>();
Box<Object> box = boxOfIntegers; // this is actually invalid
box.add("I'm a string in a box of integers. Ouch!");
答案 1 :(得分:0)
您的问题是一个经典的通用拼图。通常我们的大脑足够聪明,可以从已知的规则中推断出新的规则,但泛型的情况并非如此。您的问题说明了通配符的两个常见问题:
List<Box<Object>>
分配给List<Box<?>>
add()
List<Box<?>>
致电List<?>
第一个问题的解决方案是泛型是不变的:除了涉及通配符之外,没有给类型变量赋予什么类型的子类型关系。即使Box<Object>
是Box<?>
的子类型,子类型关系也不适用于封闭列表。
问题#2的规则是通配符不是递归地捕获。实际上new ArrayList<Box<?>>()
是有效的表达式,而new ArrayList<?>()
则不是。{1}}。另外,正如我之前所说,您可以向List<Box<?>>
添加元素,因为泛型类型List<E>
的实例化会产生:
// This actually doesn't compile, it's just an explanation of the
// instantiation process
public interface List<Box<?>> {
void add(Box<?> box);
}
答案 2 :(得分:0)
List<A>
是List<?>
的子类型,其中A
是一种类型(满足通配符的边界,如果有的话)。
但是,List<A>
不是List<B>
的子类型,如果A
和B
是不同的类型(不管{{1}之间的任何子类型关系如何}和A
)。
您可能已经看到B
不是List<String>
的子类型的情况,即使List<Object>
是String
的子类型。 (我不会在这里说明理由。)
Object
不是List<Box<String>>
的子类型,即使List<Box<?>>
是Box<String>
的子类型,也会发生同样的事情。请注意,即使某处有某个Box<?>
,它也只是?
类型的一部分。 Box<?>
不会在?
参数的级别上执行操作,因此不允许您使用不同类型的列表。
如果您想要一种可以接受List
和List<Box<String>>
等的类型,您可能需要使用List<Box<Integer>>
。请注意,此处顶级有List<? extends Box<?>>
。这允许?
的类型参数为List
的任何子类型,其中包括Box<?>
,Box<String>
。