1

我有三种类型,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吗?如何使这个工作?

4

1 回答 1

2

使用带有上限通配符的声明

doSomething(List<? extends X>)

List<S>不是的子类型List<T>即使S是的子类型T

您可以用非常简单的术语来思考为什么会这样。

如果DogCat是 的子类型Animal并且你的方法是doSomething(List<Animal> pets),那么在方法里面你可能addCat. 但是如果pets作为 a 传递List<Dog>呢?你可能会出现过敏反应。

输入通配符

因此,您可以使用通配符来执行此操作。通配符参数化类型 表示List<? extends Animal>:“(来自)所有参数化类型的集合 - 通过调用泛型类型形成List<T>- 类型参数是任何类型(通常称为“未知类型”) - 这是Animal(包括的)”。

暗示这是一个潜在的无限集合,因为您可能有无限数量的子类型Animal (和 List mumble mumble 的子类型使问题 mumble 复杂化)

”参数

使用List<? extends Animal>表示“我同意将此列表中的所有内容视为,充其量是一个Animal”。简单来说,您不能再add(e)对该列表进行任何操作,因为在方法内部您不知道它是 a还是List<Dog>在调用站点。但是,您可以使用该列表参数中的任何项目和它(假设是 上的方法)。它是一个“ in ”参数:它为方法提供数据。List<Cat>List<Animal>get(index)feed()feed()Animal

tldr:extends边界意味着一个“输入”变量(您从中提取数据的变量,而不是您将数据放入的变量)

”参数

如果您想add(e)进入Dog列表,您需要通过声明将方法声明更改为“ out ”变量doSomething(List<? super Dog>)。现在您在说“我可以将此列表视为包含任何超类型Dog”的类型:在调用站点它可能是aList<Dog>或. 您现在可以使用 a或 的子类型,例如 a : all 将与传递的任何可能的列表类型兼容。您不能添加 a ,因为这没有任何意义:调用站点的列表仍然可以是 a ,而不是 a 。List<Animal>List<Object>add(e)DogDogMongrelCatList<Dog>List<Animal>

tldr:它是一个“ out ”参数:它从方法内部“存储”数据,(因此可以将其提供回调用站点)。

参考:Java 教程 >上界通配符

于 2015-02-25T08:53:15.790 回答