9

我有一个功能

public static void bar (final List<List<?>> list)
{
}

我可以用通配符 ( <?>)调用

bar(new ArrayList<List<?>>());

但不是其他类型(例如String

// The method bar(List<List<?>>) in the type Foo is not
// applicable for the arguments (ArrayList<List<String>>)
bar(new ArrayList<List<String>>());

然而,这适用于类似的功能

public static void foo(List<?> l)
{
}

public static void main(String[] args)
{
    // no error
    foo(new ArrayList<String>());
}

您能否解释一下,为什么编译器在第一种情况下抱怨,而在第二种情况下却没有?

4

1 回答 1

4

您应该将您的方法声明为:

private void bar(final List<? extends List<?>> lists) {...}

在这种情况下,调用bar(new ArrayList<List<String>>());会起作用。

说明

简而言之:

List<SomeType>- 编译器将期望调用具有完全相同的类型。 List<? extends SomeType>- 编译器将期望调用与兼容(子类)的类SomeType

在您的情况下,定义

void bar (final List<List<?>> list)

将期望一个其定义准确的参数List<List<?>>() nestedList;

另一方面,当您将方法指定为:

void bar(final List<? extends List<?>> lists)

然后你说你有一个列表,其类型的上限为List<?>,因此ArrayList<String>将是嵌套列表的有效候选者

来自Oracle 文档

这里有一个很小但非常重要的区别:我们用 List 替换了 List 类型。现在 drawAll() 将接受 Shape 的任何子类的列表,因此我们现在可以根据需要在 List 上调用它。

列表是有界通配符的一个示例。这 ?代表未知类型,就像我们之前看到的通配符一样。但是,在这种情况下,我们知道这种未知类型实际上是 Shape 的子类型。(注意:它可以是 Shape 本身,也可以是某个子类;它不需要从字面上扩展 Shape。)我们说 Shape 是通配符的上限。

于 2013-07-02T08:23:23.300 回答