泛型-下限/上限通配符行为?

4

我正在尝试理解下限和上限通配符的行为。

在尝试编译以下代码时遇到了问题。

Collection<? extends Object> c = new ArrayList<Object>();
c.add(new Object()); // Compile time error

为了解决这个问题,我尝试使用下限通配符。幸运或不幸的是,代码编译通过了,但也带来了很多困惑。

Collection<? super Object> c = new ArrayList<Object>();
 c.add(new Object()); // Compiles fine

有人能解释一下这两个代码片段是如何工作的吗?如果有人能提供额外的示例/链接,那就太好了。
如果我上面有什么错误,请纠正我。
谢谢。

@JornVernee 同意这与 PECS 有关。 - gati sahu
2个回答

6

? 表示一个“未知类型”。

Collection<? extends Object> 表示一种对象类型的集合。这个“对象类型”可以是任何 Object 的子类或者 Object 本身。但具体是哪种类型呢?编译器并不知道。

当你尝试向集合中添加一个新的 Object 时,你不能这样做。这是因为集合的类型是未知的。它可能是一个 ArrayList<String>,也可能是一个 HashSet<Integer>。所以编译器说:

“如果这个集合是 ArrayList<String> 呢?你不能把一个 Object 放进去!”

基本上,编译器太谨慎了,不会让你这样做。


Collection<? super Object> 表示一种对象类型的集合。这个“对象类型”可以是任何 Object 的超类或者 Object 本身。在这里只能是一个东西 - Object,因为 Object 没有超类。这就是为什么你可以向集合中添加一个新的 Object

即使 Object 有一个超类,你仍然可以添加一个 new Object()。假设 Object 的超类是 MyClass。现在,集合可以是 MyClass 或者 Object 的集合。无论哪种情况,你都可以向其中添加一个 Object


我完全理解了关于 Collection<? extends Object> 的部分,这很有道理。但是在 Collection<? super Object> 的情况下,为什么它会接受 任何 SupersClassObject 类本身呢? - Yahya
这只是什么意思?super Object的意思。如果A extends B,你可以将B添加到A的集合中。这里也是一样的。@Yahya - Sweeper
@JornVernee 噢,这是个打字错误。我的意思是你可以将 A 添加到 B 的集合中。 - Sweeper
@Sweeper 谢谢,我明白你的意思了。我认为你最后一段解释得足够清楚了。但是在脑海中理解还是有些棘手的。 - Jorn Vernee

0

让我们改变类的类型,使其更易于理解。 您的第一个示例已更改为 数字

Collection<? extends Number> c = new ArrayList<Number>();

意味着有 ? 个类型为 Number 的对象。因此,它可以是任何 extends Number 的东西,例如 IntegerDoubleFloatBigInteger 等等。因此,您无法保证列表中驻留的是哪种类型的 Number 对象。

List<Integer> // only allows Integer
List<Double> // only allows Double
List<Float> // only allows Float

这就是为什么你不能向<? extends Number>添加任何内容,因为它可能是上述列表中的任何一个。

另一种方式是使用<? super Number>。这意味着列表中的每个对象都是Number的祖先。在这种情况下,您可以添加来自Number的超类型/类型的任何内容。使用? super Number可以保证其中的所有内容都是Number

但是,您无法保证实际类型,例如:

list.get(0); // is a Number, but could be a Integer
list.get(1); // is a Number, but could be a Float
list.get(2); // is a Number, but could be a Double

简而言之,使用extends进行读取,使用super进行添加。

这里有一张来自文档https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html的图表。

enter image description here

这里是Jon Skeet对于<? super Number>的解释

https://dev59.com/413Ua4cB1Zd3GeqP9RrJ#8083260


1
关于 ? super 的部分需要修改。你把大部分都搞反了。如果边界是 ? super Number,那么 IntegerFloatDouble 都不可能。 - John Kugelman
@JohnKugelman 但是这些类型是“数值”。它们不一定需要是超类型。 - Murat Karagöz
1
IntegerNumber的子类。? super Number匹配超类(或Number本身)。Number的唯一超类是Object - John Kugelman
@JohnKugelman 是的,这些是数字,例如 http://ideone.com/fu5Rvt - Murat Karagöz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接