4

以下代码导致编译时错误:

List 类型中的方法 add(capture#1-of ? extends Object) 不适用于参数 (String)

代码 :

List<? extends Object> a1 = new ArrayList();
a1.add("string");

错误在行:

a1.add("string");

由于类 String 从 Object 扩展,为什么 ref a1 不接受 String 类型?

4

3 回答 3

4

? extends Object意思是“一些未知X的扩展类型Object”。通过尝试将 a 添加String到集合中,您实际上是在声明X = String,编译器无法验证。据编译器所知,X也可以是Integer或完全不同的东西。

换句话说List<? extends Object>,并不意味着“任何延伸的东西Object”。一个简单的List<Object>意思。

于 2013-04-27T12:09:54.657 回答
4

我推荐阅读这篇文章,http://java.dzone.com/articles/covariance-and-contravariance。(斜体是我的补充)

总之,<? extends Object>当我们只打算从结构中取出通用值时,我们使用协方差。<? super Object>当我们只打算将通用值放入一个结构中时,我们使用逆变,而<Object>当我们打算同时做这两种情况时,我们使用不变量。

您将列表定义为持有协变 Object 类型,这意味着您可以编写Object o = a1.get(1)但不能编写a1.add("foo"). 如果您希望能够添加对象但不能取回它们,那么您需要像这样定义您的列表:

List<? super Object> a1 = new ArrayList<>();

有点不幸,在我看来,语言作者使用术语extendandsuper来表示协变和逆变,尤其是在上面的例子中,因为没有Object.

于 2013-04-27T12:16:05.723 回答
1

List<? extends Object>可以与每种类型的列表一起使用。

您如何看待,例如,让它添加任何对象是否安全

List<? extends Object> a1 = new ArrayList<Integer>();
a1.add("string");

唯一要添加的安全值是null因为它不属于任何特定类型。

为了摆脱这个问题,您可以使用例如List<String> a1 = new ArrayList<String>()List a1 = new ArrayList()

于 2013-04-27T12:13:25.700 回答