了解Javagenerics中的通配符

我不确定为什么以下代码中的最后一个语句是非法的。 Integer应该是一个子类型? ,为什么我不能把它分配给b

 List a = new ArrayList(); a.add("foo"); // b is a List of anything List b = a; // retrieve the first element Object c = b.get(0); // This is legal, because we can guarantee // that the return type "?" is a subtype of Object // Add an Integer to bbadd(new Integer (1)); 

关键是b指的是某种类型的列表,但编译器不知道该类型是什么,所以它不知道向它添加一个Integer是否有效。 同样也是一件好事,给出你的例子 – 你要将一个Integer添加到最初创建的对象中以保存字符串列表。 当然,这些信息在Java执行时会丢失 – 但编译器会尽量保证您的安全。

有关更多信息,请参阅Javagenerics常见问题解答 。

Integer不是一个子类型? (一定)。 ? 是一个通配符; 你应该把它解释为“未知”。

因此ListList 。 您可以将任何您喜欢的内容添加到List

引用“b”被声明为List,即“我还不知道的事物列表”。 您可以为此引用分配几乎任何实现,例如List。 这就是禁止通过此引用向列表添加任何内容的原因。

这是因为我们不能保证Integer是参数类型“?”的子类型。

看看这个:

 Object c = b.get(0); 

这有效吗? 将永远是Object的子类型。

集合和generics的粗略经验如下:

  • Collection是一个Collection,你可以从中获得一个Foo,你可以添加一个Foo。
  • Collection Collection是一个Collection,你可以从中获得Foo, 但是你不能添加任何东西

为什么会这样? 因为当你说Collection ,你向那个引用的用户承诺他们可以在有问题的对象上调用add(Foo elem)方法。 另一方面,当您使用通配符版本时,您将“真实”参数类保留为引用用户的秘密 – 他们知道从集合中提取的任何元素都可以转换为Foo,但不能他们可以添加任何Foo。

为什么这有用? 因为有许多,很多很多情况下你会编写想要遍历Collection的方法,其元素都是Foos,但你永远不需要添加任何元素。 像这样:

 public Foo findAFooThatILike(Collection foos); 

在这里使用通配符意味着该方法将接受Collection作为其参数以及Collection的任何子类型的集合; 例如,如果Bar是Foo的子类型,则上面的签名意味着您可以将Collection传递给该方法。

另一方面,如果你写了这样的签名:

 public Foo findAFooThatILike(Collection foos); 

…那么你将无法传入Collection作为参数。 为什么? 因为要成为Collection ,它需要支持add(Foo elem)方法,而Collection则不需要。

请注意,这些经验法则仅适用于Collection接口和类。 (另请注意, Collection并不意味着“只读Foo集合”;当您不知道精确的元素类型时,许多从集合中删除元素的方法仍然有效)。

那么,回到原来的问题: ListList相同List List 。 它是一个列表,您可以从中获取对象实例的引用,但您无法安全地添加任何内容。

以下是关于generics可以做什么和不做什么的简短摘要:

  List listOfAnyNumbers = null; List listOfNumbers = null; List listOfIntegers = null; listOfIntegers = listOfNumbers; // Error - because listOfNumbers may contain non-integers listOfNumbers = listOfIntegers; // Error - because to a listOfNumbers you can add any Number, while to listOfIntegers you cannot. listOfIntegers = listOfAnyNumbers; // Error - because listOfAnyNumbers may contain non-integers listOfAnyNumbers = listOfIntegers; // OK - because listOfIntegers is a list of ?, where ? extends Number. listOfNumbers = listOfAnyNumbers; // Error - because listOfAnyNumbers may actually be List, to which you cannot add any Number. listOfAnyNumbers = listOfNumbers; // OK - because listOfNumbers is a list of ?, where ? extends Number. 

List <?>表示键入未知类型的列表。这可以是Integer,String或XYZ类的List。

由于您不知道键入的列表类型是什么,因此您只能从集合中读取,并且您只能将读取的对象视为Object实例。

如果要在通配符通用集合中插入元素,请转到超级通配符边界。