4

当 String 和 Integer 不是 Object 的超类时,为什么以下是合法的?

List<? super Object> mylist = new ArrayList<Object>();
mylist.add("Java"); // no compile error
mylist.add(2);

我知道通配符指南使用下限通配符和 super 用于“输出”变量,但在这种情况下似乎 Object 不能用作“下限”。

这也是允许将任何类型添加到列表中的唯一方法吗?

4

3 回答 3

4

这真的很简单。请记住,在 Java 中,子类型的实例也是其超类型的实例。

看签名add

public boolean add(E e)

这意味着无论您传递什么类型E或任何子类型的东西E

你有一个List<? super Object>. 因此,您可以传递给myList.add()任何类型为? super Object(可能是其超类型的未知类型Object)或其任何子类型的东西。

Integer 是 所包含的所有类型的子类型? super Object吗?当然。Integer是 的子类型Object,它是 所包含的所有类型的子类型? super Object(当然,在这种情况下,只Object满足这个)。

您将类型参数与可以传递给方法的东西混淆了。的类型参数List<? super Object>一个未知类型,它是 的超类型Object,因此IntegerString不能是实际的类型参数。事实上,在这种情况下,唯一有效的实际类型参数是Object. 但是,当您将某些东西传递给该方法时,您要问的是,我要传递的是子类型吗?答案是肯定的。

于 2012-08-10T18:45:44.007 回答
3

这是因为 Object 是 Integer 和 String 的超类。您正在以相反的方式解释通用关系。

编辑

想想这种情况:

List<? extends myClass> listOfMyClass = new ArrayList<Object>();

在这种情况下,您将得到一个Object类型元素列表,但必须遵守listOfMyClass列表声明添加的限制。

您将能够将属于myClass层次结构的任何对象添加到列表中。ArrayList实现接口的将在请求时List保存(并返回)Object类型元素。

当然,你可以这样定义:

List<? extends myClass> listOfMyClass = new ArrayList<mySuperClass>(); 

正如您现在可能看到的,ArrayList必须包含具有相同类型或超类型的对象myClass,在这种情况下,就是mySuperClass. 此列表将返回mySuperClass请求的对象。

ClassX作为不属于 mySuperClass 层次结构的类,以下行将无法编译:

List<? extends myClass> listOfMyClass = new ArrayList<ClassX>(); 

那是因为ClassX不是 的超类myClass

于 2012-08-10T18:06:36.450 回答
3

我同意这令人困惑,但这就是正在发生的事情。

在这行代码中:

List<? super Object> mylist...

您说的myList是 a List,其中每个元素都可以是 is 的类型Object或 的超类Object。但是,您只是在myList此处声明类型。

通配符的作用是限制您对myList.

然后,你这样做:

List<? super Object> mylist = new ArrayList<Object>();

现在你正在做的是实例化一个ArrayList<Object>. 您的下限通配符用于检查这是否有效。它是有效的,因为Object匹配? super Object. 此时,您有一个List<Object>并且您随后的方法调用被允许。

于 2012-08-10T18:24:28.147 回答