List<?> 或者 List<Object>

20

我有一个方法,其参数应该是"任何东西的列表(List of anything)"。该方法不会修改列表的内容。将此方法定义为以下哪个更加正确?

void foo(List<?> list) {
}
或者
void foo(List<Object> list) {
}

那具体有什么区别呢?

6个回答

18

简短回答:使用List<?>可以接受类似于List<String>的内容,而使用List<Object>则不能。

这在官方泛型教程中有所讨论,此处此处有相关内容。

[...] 这里是使用泛型和新的for循环语法进行编写的天真尝试:

   void printCollection(Collection<Object> c) {
       for (Object e : c) {
           System.out.println(e);
       }
   }
问题在于这个新版本比旧版本要不实用得多。旧代码可以使用任何类型的集合作为参数进行调用,但新代码只接受 Collection<Object>,正如我们刚刚演示的那样,并非所有类型的集合的超类型!
那么什么是所有种类集合的超类型呢?它被写成 Collection<?>(读作“未知类型的集合”),也就是说,元素类型可以匹配任何东西的集合。 这被称为通配符类型,理由显而易见。我们可以这样写:
   void printCollection(Collection<?> c) {
       for (Object e : c) {
           System.out.println(e);
       }
   }

现在,我们可以使用任何类型的集合来调用它。


5
List<Object> 的参数化类型是 Object,这意味着你可以将所有对象添加到列表中。
然而,List<?> 表示的是未知类型列表。只要你不打算向列表中添加任何内容,它基本上与 List<Object> 相同,但你需要关注以下情况:
List<?> unknownList = new ArrayList<String>();
unknownList.add(new Object()); //Compilation error.

在这种情况下,? 的意思是您只能添加 String 值或其子类型的值。

如果您只是要遍历列表并检索值,则 List<?>List<Object> 本质上是相同的。
更多信息请参见此处

1
你不能向List<?>中添加除了null以外的任何东西。 - TigerBear
如果你正在使用一个未知列表,是的。 - Buhake Sindi

1

它们两者相当不同

void foo(List<?> list)

意味着你期望得到某个列表,但你没有指定它是什么

void foo(List<Object> list)

表示您期望传递的列表是对象列表,因此如果尝试传递List,则不会被接受(与第一个声明相反)

常见错误是假设List<String>子类型,可以说是List<Object>,即使String是Object的子类型也不是这种情况。


0

如果您不想修改列表,则使用 List<?> 更合适。

这样,您可以将例如 List<String>List<BigInteger> 传递给您的方法。


0

你需要使用void foo(List<?> list),否则你将无法传递例如List<String>

如果你使用void foo(List<Object> list),那么你只能传递List<Object>

这是因为在Java中,泛型不是协变的: List<String>不是List<Object>的子类型。


0
这个教程的第三和第四部分应该能回答你的问题:

http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf

引用自教程:

一般来说,如果Foo是Bar的子类型(子类或子接口),而G是某个泛型类型声明,则G<Foo>不是G<Bar>的子类型....

... Collection<Object>,正如我们刚刚证明的那样,它不是所有类型集合的超类型! 那么所有类型集合的超类型是什么?它被写成Collection<?>(发音为“未知集合”),即元素类型与任何类型匹配的集合。

然而,在严格假设方法foo将保持集合不变的情况下,实现上应该没有区别。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接