以下代码导致编译时错误:
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 类型?
以下代码导致编译时错误:
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 类型?
? extends Object
意思是“一些未知X
的扩展类型Object
”。通过尝试将 a 添加String
到集合中,您实际上是在声明X = String
,编译器无法验证。据编译器所知,X
也可以是Integer
或完全不同的东西。
换句话说List<? extends Object>
,并不意味着“任何延伸的东西Object
”。一个简单的List<Object>
意思。
我推荐阅读这篇文章,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<>();
有点不幸,在我看来,语言作者使用术语extend
andsuper
来表示协变和逆变,尤其是在上面的例子中,因为没有Object
.
List<? extends Object>
可以与每种类型的列表一起使用。
您如何看待,例如,让它添加任何对象是否安全
List<? extends Object> a1 = new ArrayList<Integer>();
a1.add("string");
唯一要添加的安全值是null
因为它不属于任何特定类型。
为了摆脱这个问题,您可以使用例如List<String> a1 = new ArrayList<String>()
或List a1 = new ArrayList()