我不确定为什么以下代码中的最后一个语句是非法的。 Integer
应该是?
的子类型,为什么我不能将其分配给b
?
List<String> a = new ArrayList<String>();
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 b.
b.add(new Integer (1));
答案 0 :(得分:11)
关键是b
是指某些类型的列表,但编译器不知道该类型是什么,因此它不会知道是否有效添加Integer
。同样也是一件好事,给出了您的示例 - 您将向最初创建的对象添加Integer
以保存字符串列表。当然,这些信息在Java执行时会丢失 - 但编译器会尽量保证您的安全。
有关 lot 的更多信息,请参阅Java generics FAQ。
答案 1 :(得分:3)
Integer
不是?
的子类型(必要)。 ?
是一个通配符;你应该把它解释为“未知”。
因此List<?>
与List<Object>
不同。您可以将您喜欢的任何内容添加到List<Object>
。
答案 2 :(得分:2)
引用“b”被声明为List,即“我还不知道的事物列表”。 您可以为此引用分配几乎任何实现,例如List。这就是禁止通过此引用向列表添加任何内容的原因。
答案 3 :(得分:1)
这是因为我们不能保证Integer是参数类型“?”的子类型。
看看这个:
Object c = b.get(0);
这是有效的吗?将始终是Object的子类型。
答案 4 :(得分:1)
对于集合和泛型的粗略经验法则如下:
Collection<Foo>
是一个集合,你可以从中获得一个Foo,你可以添加一个Foo。Collection<? extends Foo>
是一个集合,您可以从中获取Foo,但是您无法添加任何内容。为什么会这样?因为当您说Collection<Foo>
时,您对该引用的用户承诺,他们可以在相关对象上调用add(Foo elem)
方法。另一方面,当您使用通配符版本时,您将“真实”参数类保留为引用用户的秘密 - 他们知道从集合中提取的任何元素都可以强制转换为Foo,而不是他们可以添加任何Foo。
为什么这有用?因为有许多,很多很多情况下你会编写想要遍历Collection的方法,其元素都是Foos,但你永远不需要添加任何元素。像这样:
public Foo findAFooThatILike(Collection<? extends Foo> foos);
在这里使用通配符意味着该方法将接受Collection<Foo>
作为其参数以及Foo的任何子类型的集合;例如,如果Bar是Foo的子类型,则上面的签名意味着您可以将Collection<Bar>
传递给该方法。
如果另一方面,你写了这样的签名:
public Foo findAFooThatILike(Collection<Foo> foos);
...然后你不能够传递Collection<Bar>
作为参数。为什么?因为某些内容属于Collection<Foo>
,所以需要支持add(Foo elem)
方法,而Collection<Bar>
则不需要。{/ p>
请注意,这些经验法则仅适用于Collection接口和类。 (另请注意,Collection<? extends Foo>
并不意味着“只读Foo集合”;当您不知道精确的元素类型时,许多从集合中删除元素的方法仍然可以工作。
所以,回到原来的问题:List<?>
与List<? extends Object>
相同。它是一个列表,您可以从中获取对象实例的引用,但您无法安全地添加任何内容。
答案 5 :(得分:1)
以下简要概述了您可以和不能使用泛型的内容:
List<? extends Number> listOfAnyNumbers = null;
List<Number> listOfNumbers = null;
List<Integer> 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<Float>, to which you cannot add any Number.
listOfAnyNumbers = listOfNumbers; // OK - because listOfNumbers is a list of ?, where ? extends Number.
答案 6 :(得分:0)
列表与LT;?&GT;表示键入未知类型的列表。这可以是整数,字符串或XYZ类的列表。
由于您不知道键入的列表类型,您只能从集合中读取,并且您只能将读取的对象视为对象实例。
如果要在通配符通用集合中插入元素,请转到超级通配符边界。