我有三种类型,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>>
A本质上不应该是X吗?如何使其发挥作用?
最佳答案
使用带有 upper bounded wildcard 的声明
doSomething(List<? extends X>)
List<S>
不是 List<T>
的子类型即使S
是 T
的子类型
你可以用非常简单的方式思考为什么会这样。
如果Dog
和Cat
是 Animal
的子类型你的方法是 doSomething(List<Animal> pets)
,然后在该方法中您可能 add
一个Cat
。但如果pets
呢?被传递为 List<Dog>
?您可能会出现过敏 react 。
输入通配符
因此,您可以使用通配符来执行此操作。 通配符参数化类型 List<? extends Animal>
表示:“(来自)所有参数化类型的集合 - 通过调用泛型类型 List<T>
形成 - 具有任何类型的类型参数(通常称为“未知” type") - 这是 Animal
(包含)的子类型。
暗示这是一个潜在的无限集,因为您可以拥有无限数量的 Animal
子类型(以及 List mumble mumble 使问题 mumble 复杂化的子类型)。
“in”参数
使用List<? extends Animal>
说“我同意将此列表中的所有内容最多视为Animal
”。简单来说,您不能再add(e)
该列表中的任何内容,因为在方法内部您不知道它是否是 List<Dog>
, List<Cat>
或List<Animal>
在调用站点。但是您可以get(index)
该列表参数中的任何项目和 feed()
它(假设 feed()
是 Animal
上的方法)。它是一个“in”参数:它向方法提供数据。
tldr:安extends
绑定(bind)意味着一个“in”变量(您从中提取数据的变量,而不是您将数据放入其中的变量)
“输出”参数
如果你想add(e)
一个Dog
在列表中,您需要通过声明 doSomething(List<? super Dog>)
将方法声明更改为“out”变量。现在你说“我可以将此列表视为包含 Dog
父类(super class)型的任何类型”:在调用站点,它可能是 List<Dog>
, List<Animal>
或List<Object>
。您现在可以add(e)
要么 Dog
,或 Dog
的子类型 ,就像 Mongrel
:all 将与传递的任何可能类型的列表兼容。您无法添加Cat
因为这没有任何意义:调用站点的列表仍然可能是 List<Dog>
,不是List<Animal>
.
tldr:它是一个“out”参数:它“存储”方法内部的数据(因此可以将其提供回调用站点)。
引用:Java 教程 > Upper bounded wildcards
关于java - Java 中的参数化类型不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28714715/