Java泛型通配符列表与通配符列表之间的区别?

时间:2015-01-03 09:11:11

标签: java generics

为什么

List<?> list = new ArrayList<Object>();

同时

List<Box<?>> boxList = new ArrayList<Box<Object>>();

是不允许的

List<? extends Box<?>>的含义也是如此。

3 个答案:

答案 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>的子类型,如果AB是不同的类型(不管{{1}之间的任何子类型关系如何}和A)。

您可能已经看到B不是List<String>的子类型的情况,即使List<Object>String的子类型。 (我不会在这里说明理由。)

Object不是List<Box<String>>的子类型,即使List<Box<?>>Box<String>的子类型,也会发生同样的事情。请注意,即使某处有某个Box<?>,它也只是?类型的一部分。 Box<?>不会在?参数的级别上执行操作,因此不允许您使用不同类型的列表。

如果您想要一种可以接受ListList<Box<String>>等的类型,您可能需要使用List<Box<Integer>>。请注意,此处顶级有List<? extends Box<?>>。这允许?的类型参数为List的任何子类型,其中包括Box<?>Box<String>