我有三种类型,A,B和X
A<T extends Object> extends X
B extends Object
并且有这个api电话
doSomething(List<X>)
我正在打这个电话
doSomething(ImmutableList.<A<B>>of(new A<B>(), new A<B>()))
但我收到错误:
List<X> cannot be applied to ImmutableList<A<B>>
不应该基本上是X吗?如何使这个工作?
答案 0 :(得分:2)
doSomething(List<? extends X>)
即使List<S>
是List<T>
的子类型, S
也不是T
的子类型
你可以用非常简单的方式思考这个问题。
如果Dog
和Cat
是Animal
的子类型且您的方法是doSomething(List<Animal> pets)
,那么您可以在方法内add
Cat
。但是如果pets
作为List<Dog>
传递了怎么办?你可能会有过敏反应。
输入通配符
因此,您可以使用通配符来执行此操作。 通配符参数化类型 List<? extends Animal>
表示:“(一种类型)所有参数化类型的集合 - 通过调用泛型类型List<T>
形成 - 使用类型参数< em>任何类型(通常称为“未知类型”) - 这是Animal
(包括)的子类型。“
暗示这是一个潜在的无限集合,因为你可能有无数个Animal
的子类型(和List mumble的子类型混淆使问题混淆)。
“ ”参数
使用List<? extends Animal>
说“我同意将此列表中的所有内容视为Animal
”。简单来说,您不能再add(e)
该列表中的任何内容,因为在该方法中,您不知道它在调用网站上是List<Dog>
,List<Cat>
还是List<Animal>
。但是,您可以get(index)
来自该列表参数的任何项目feed()
它(假设feed()
是Animal
上的方法)。它是一个“ in ”参数:它为方法提供数据。
tldr:extends
绑定意味着一个“in”变量(一个从中提取数据的变量,而不是一个用于输入数据的变量)
“ out ”参数
如果您希望将add(e)
Dog
添加到列表中,则需要通过声明doSomething(List<? super Dog>)
将方法声明更改为“ out ”变量。现在你说“我可以将此列表视为保留任何类型为Dog
”的超类型:在调用站点,它可能是List<Dog>
,{{1 }或List<Animal>
。您现在可以List<Object>
add(e)
或Dog
的子类型,例如Dog
:所有内容都与任何可能的内容兼容传递的列表类型。您无法添加Mongrel
,因为这没有意义:调用网站上的列表可能仍然是Cat
,而不是List<Dog>
。
tldr:这是一个“ out ”参数:它“存储”方法内部的数据,(因此可以将其提供回调用站点)。
参考:Java教程&gt; Upper bounded wildcards