Java 中的参数化类型不匹配
Parameterized Type Mismatch in Java
我有 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 吗?如何让它工作?
的声明
doSomething(List<? extends X>)
List<S>
不是 List<T>
的子类型,即使 S
是 T
的子类型
你可以用很简单的方式思考为什么会这样。
如果 Dog
和 Cat
是 Animal
的子类型并且您的方法是 doSomething(List<Animal> pets)
,那么在方法内部您可能 add
a Cat
.但是,如果 pets
作为 List<Dog>
传递怎么办?您可能会出现过敏反应。
输入通配符
因此您可以使用通配符来做到这一点。 通配符参数化类型 List<? extends Animal>
表示:“(来自)所有参数化类型的集合 - 通过调用泛型类型 List<T>
形成 - 带有类型参数那是 任何类型(通常称为“未知类型”)——它是 Animal
(含)的子类型。
暗示这是一个潜在的无限集合,因为您可能有无限数量的 Animal
子类型(以及 List mumble mumble 使问题复杂化的子类型 mumble) .
"在"参数
使用 List<? extends Animal>
表示“我同意最多将此列表中的所有内容视为 Animal
”。简单来说,您不能再 add(e)
该列表中的任何内容,因为在方法内部您不知道调用站点上它是 List<Dog>
、List<Cat>
还是 List<Animal>
.但是,您可以 get(index)
该列表参数中的任何项目并 feed()
它(假设 feed()
是 Animal
上的方法)。它是一个“in”参数:它为方法提供数据。
tldr:extends
绑定意味着一个 "in" 变量(您从中提取数据的变量,而不是您将数据放入的变量)
"输出"参数
如果你想 add(e)
一个 Dog
进入列表你需要通过声明 doSomething(List<? super Dog>)
。现在你说的是“我可以将这个列表视为包含 Dog
的超类型的任何类型”:在调用站点它可能是 List<Dog>
, List<Animal>
或 List<Object>
。您现在可以 add(e)
Dog
或 Dog
的 子类型 ,就像 Mongrel
一样:所有都将兼容任何可能传递的列表类型。您不能添加 Cat
,因为那没有任何意义:调用站点的列表仍然可以是 List<Dog>
,而不是 List<Animal>
.
tldr:它是一个“out”参数:它 "stores" 来自方法内部的数据(因此可以将其提供回调用站点)。
参考文献:Java 教程 > Upper bounded wildcards
我有 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 吗?如何让它工作?
doSomething(List<? extends X>)
List<S>
不是 List<T>
的子类型,即使 S
是 T
你可以用很简单的方式思考为什么会这样。
如果 Dog
和 Cat
是 Animal
的子类型并且您的方法是 doSomething(List<Animal> pets)
,那么在方法内部您可能 add
a Cat
.但是,如果 pets
作为 List<Dog>
传递怎么办?您可能会出现过敏反应。
输入通配符
因此您可以使用通配符来做到这一点。 通配符参数化类型 List<? extends Animal>
表示:“(来自)所有参数化类型的集合 - 通过调用泛型类型 List<T>
形成 - 带有类型参数那是 任何类型(通常称为“未知类型”)——它是 Animal
(含)的子类型。
暗示这是一个潜在的无限集合,因为您可能有无限数量的 Animal
子类型(以及 List mumble mumble 使问题复杂化的子类型 mumble) .
"在"参数
使用 List<? extends Animal>
表示“我同意最多将此列表中的所有内容视为 Animal
”。简单来说,您不能再 add(e)
该列表中的任何内容,因为在方法内部您不知道调用站点上它是 List<Dog>
、List<Cat>
还是 List<Animal>
.但是,您可以 get(index)
该列表参数中的任何项目并 feed()
它(假设 feed()
是 Animal
上的方法)。它是一个“in”参数:它为方法提供数据。
tldr:extends
绑定意味着一个 "in" 变量(您从中提取数据的变量,而不是您将数据放入的变量)
"输出"参数
如果你想 add(e)
一个 Dog
进入列表你需要通过声明 doSomething(List<? super Dog>)
。现在你说的是“我可以将这个列表视为包含 Dog
的超类型的任何类型”:在调用站点它可能是 List<Dog>
, List<Animal>
或 List<Object>
。您现在可以 add(e)
Dog
或 Dog
的 子类型 ,就像 Mongrel
一样:所有都将兼容任何可能传递的列表类型。您不能添加 Cat
,因为那没有任何意义:调用站点的列表仍然可以是 List<Dog>
,而不是 List<Animal>
.
tldr:它是一个“out”参数:它 "stores" 来自方法内部的数据(因此可以将其提供回调用站点)。
参考文献:Java 教程 > Upper bounded wildcards