我有一个功能
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>());
}
你能解释一下,为什么编译器会在第一种情况下抱怨而不是在第二种情况下抱怨?
答案 0 :(得分:7)
您的问题在这里得到了完美的解释: multiple nested wildcard - arguments not applicable
看看接受的答案。提供的链接应该回答您的所有Java通用问题。
答案 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 docs:
这里有一个很小但非常重要的区别:我们已经取代了 类型列表与列表。现在drawAll()会 接受Shape的任何子类的列表,所以我们现在可以在a上调用它 列出我们是否想要。
List是有界通配符的示例。的? 代表一种未知类型,就像我们之前看到的通配符一样。 但是,在这种情况下,我们知道这种未知类型实际上是一种 Shape的子类型。 (注意:它可能是Shape本身,或者是某些子类; 它不需要字面上扩展Shape。)我们说Shape是上层 通配符的界限。