我一定错过了关于Java中泛型的东西,但为什么这不起作用?
List<String> list = new ArrayList<String>();
无法发送至:
method( List<Object> );
但它不起作用?怎么样?
但如果方法是:
method( Object o )
它可以用于:
method( new String("hello") )
没有任何问题
q1)String确实扩展了Object,为什么不能将它传递给?
List<Object>
q2)以及为什么
method( List<? extends Object> )
工作?有什么区别?
答案 0 :(得分:10)
注意:
List<String> stringList = new ArrayList<String>();
List<Object> objectList = stringList; // if this was allowed…
objectList.add(new Object());
String s = stringList.get(0); // …this would throw a ClassCastException
显然,不允许这样做,因为List<String>
之后会包含Object
,从而丢弃了仿制品旨在为您提供的所有类型安全性。
答案 1 :(得分:7)
List<String>
不是List<Object>
的子类型,正如您所料。
但是,您可以像这样定义方法:
method(List<? extends String> list)
这将允许您从列表中获取字符串,但不允许输入任何内容。您可以将List<String>
或理论上的任何String子类型的List传递给方法。
您也可以将其定义为
method(List<? super String> list)
允许您将字符串放入列表中,但只能从中读取对象。然后,您可以传递List<String>
或List<Object>
。
请注意,在此示例中没有多大意义(因为您不能将String子类化),但它对其他类型层次结构有意义
答案 2 :(得分:5)
如果像这样定义method()怎么办?
void method(List<Object> list) {
list.add(new Long(1));
}
这没关系吗?哎呀,除非你传入列表<String>
!
很难解释直觉,但我可以指出List上的get()方法不会出现这样的问题,对吧?由于list只承诺返回一个Object。问题是“设置”或“添加”方法。它需要匹配超类型,而不是子类型。一般来说,限制种类在泛型土地上是双向的。所以它与简单的参数传递不同,其中子类总是正常的。
答案 3 :(得分:3)
泛型很复杂,您可能需要阅读this。 我不解释任何我在这里解释的东西就足够了。 无论如何,简短的回答是: 如果String的List可以分配给Object of List,那么可以使用List of Object作为引用,可以向它添加一些不是String的东西,从而使“List of String”定义无效。但是有可能将List of String分配给未知的List,因为未知的列表只能被读取,而不能被添加到。顺便说一下,列表?与列表相同的是什么? extends Object
答案 4 :(得分:2)
您在此处遇到的问题以Covariance命名。
基本上,如果长颈鹿是动物,为什么List<Giraffe>
不应该是List<Animal>
?这很有意义,但它可能会导致Sean mentioned等问题。
关于Java解决此问题的方式的第二个问题。 有界通配符允许您定义协变(和逆变)列表,这些列表可以安全地解决上述问题。例如,您无法将元素添加到有界通配符列表中。
答案 5 :(得分:0)
这就是为什么这不起作用的原因相同?
private void hello(List<? extends Object> l) {
l.add( new String(""));
}