列表<a> canot be sent to method( List<super-class-of-a> ) - why not?</super-class-of-a></a>

时间:2009-09-08 09:57:07

标签: java generics

我一定错过了关于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> ) 

工作?有什么区别?

6 个答案:

答案 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(""));
}