List<Object>如何成为List<? super Number>的子类型

3

在阅读书籍《Java Generics and Collections》时,在使用Super进行通配符部分,我遇到了一个例子。

public static <T> void copy(List<? super T> dst, List<? extends T> src) {
  for (int i = 0; i < src.size(); i++) {
     dst.set(i, src.get(i));
  }
}

它被称为:

Collections.<Number>copy(objs, ints);

上面的调用是有效的,其解释如下:
该调用被允许,因为`objs`的类型是`List`,它是`List`的子类型(由于`Object`是通配符所需的超类型`Number`),而`ints`的类型是`List`,它是`List`的子类型(由于`Integer`是通配符所需的子类型`Number`)。
我的疑问是:`List`如何成为`List`的子类型?

@JonSkeet 我没有正确理解 List<? super Number>,当 Object 是所有类型的超类型时,为什么 List<? super Number> 是 List<Object> 的超类型。 - Prateek
1
@Prateek:我不一定会在这里使用“子类型”,但是Object肯定满足? super Number中的通配符,不是吗? - Jon Skeet
@JonSkeet 因为 Object 是 ? super Number 的超类型,那么为什么 List<Object> 是 List<? super Number> 的子类型。yshavit 的答案涉及到逆变性,但我不明白编译器是如何理解它的。 - Prateek
2
@Prateek:再次强调,我可能不会在这种情况下使用子类型和超类型——至少不会在非常仔细地检查规范之前这样做——但我认为Object满足通配符的要求,因此该调用是有效的。(也许它确实在技术上是一个子类型;我只需要非常仔细地检查一下。) - Jon Skeet
好的。这意味着,如果我传递的不是 Object 而是 List<Number>,那么它也将是一个有效的调用,因为它也满足要求。明白了。 谢谢... - Prateek
显示剩余3条评论
3个回答

8
这里是“子类型”(subtype)的定义。当且仅当类型X的每个对象或基本类型也是类型Y时,类型X是类型Y的一个“子类型”。所以你提出的问题是,类型为List<Object>的每个对象是否也属于类型List<? super Number>,或者如何判断。

现在,部分? super Number表示“任何是Number的超类型的类型,包括Number本身”。只有两种这样的类型——NumberObject
因此,List<? super Number>是一个抽象类型,其中包含List<Number>List<Object>,除了这两种类型的子类型之外,没有其他类型。

但是List<Number>不能成为Number列表的子类型,因此只剩下List<Object>。 - Prateek
@Prateek,Number不是? super Number的有效替代品吗? - zakinster
这是一个有效的替代方案,但我对List<Object>参数感到困惑。它被称为List<? super Number>的子类型(其中List<Object>可能是有效的超类型,而不是List<Number>)。 - Prateek
@Prateek List<Object> 在技术上并不是 List<? super Number> 的子类型,它们都是 List。然而,List<Object> 可以作为 List<? super Number> 的有效替代,因为 Object 可以作为 ? super Number 的有效替代。 - zakinster
1
@zakinster。不,List<Object>绝对是List<? super Number>的子类型。 - Dawood ibn Kareem

1

? super 是 Java 中表示"逆变"的奇怪方式。

首先理解协变:当且仅当 BC 的子类型时,A<? extends B>A<? extends C> 的子类型。因此,List<? extends Number>List<? extends Object> 的子类型。

逆变则相反:当且仅当 CB 的子类型时,A<? super B>A<? super C> 的子类型。因此,List<? super Object>List<? super Number> 的子类型。


好的,那就是我需要的...谢谢 Chris。 - Prateek
1
但是如何证明这种协变性是正确的,您能解释一下吗? - Prateek
我不确定你在问什么。这只是一个逆变通用类型的定义。 - Chris Martin
1
我的意思是,编译器如何理解这种行为? - Prateek

0
也许你正在试图与描述进行斗争。可以这样想: List<? super Number> 表示它应该是一个列表,存储任何对象,只要该对象是 Number 的超类。因此,List<Object> 显然符合条件。

但是在解释中,它说List<Object>是子类型。 - Prateek

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