我有一个功能
public static void bar (final List<List<?>> list)
{
}
Run Code Online (Sandbox Code Playgroud)
我可以使用通配符调用(<?>)
bar(new ArrayList<List<?>>());
Run Code Online (Sandbox Code Playgroud)
但不是与其他类型(例如String)
// The method bar(List<List<?>>) in the type Foo is not
// applicable for the arguments (ArrayList<List<String>>)
bar(new ArrayList<List<String>>());
Run Code Online (Sandbox Code Playgroud)
然而,这适用于类似的功能
public static void foo(List<?> l)
{
}
public static void main(String[] args)
{
// no error
foo(new ArrayList<String>());
}
Run Code Online (Sandbox Code Playgroud)
你能解释一下,为什么编译器会在第一种情况下抱怨而不是在第二种情况下抱怨?
您应该将您的方法声明为:
private void bar(final List<? extends List<?>> lists) {...}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,调用bar(new ArrayList<List<String>>());就可以了。
简而言之:
List<SomeType>- 编译器将期望调用具有完全相同的类型。
List<? extends SomeType>- 编译器将期望调用与 . 兼容的类(子类)SomeType。
在你的情况下定义
void bar (final List<List<?>> list)
Run Code Online (Sandbox Code Playgroud)
将期望一个参数的定义恰好是List<List<?>>() nestedList;
另一方面,当您将方法指定为:
void bar(final List<? extends List<?>> lists)
Run Code Online (Sandbox Code Playgroud)
然后你说你有一个列表,其类型的上限为List<?>,因此ArrayList<String>将是嵌套列表的有效候选者
来自Oracle 文档:
这里有一个很小但非常重要的区别:我们用 List 替换了类型 List。现在,drawAll() 将接受任何 Shape 子类的列表,因此如果需要,我们现在可以在 List 上调用它。
List 是有界通配符的一个示例。这 ?代表未知类型,就像我们之前看到的通配符一样。然而,在这种情况下,我们知道这个未知类型实际上是 Shape 的子类型。(注意:它可以是 Shape 本身,也可以是某个子类;它不需要从字面上扩展 Shape。)我们说 Shape 是通配符的上限。