当 String 和 Integer 不是 Object 的超类时,为什么以下是合法的?
List<? super Object> mylist = new ArrayList<Object>();
mylist.add("Java"); // no compile error
mylist.add(2);
我知道通配符指南使用下限通配符和 super 用于“输出”变量,但在这种情况下似乎 Object 不能用作“下限”。
这也是允许将任何类型添加到列表中的唯一方法吗?
这真的很简单。请记住,在 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
,因此Integer
或String
不能是实际的类型参数。事实上,在这种情况下,唯一有效的实际类型参数是Object
. 但是,当您将某些东西传递给该方法时,您要问的是,我要传递的是子类型吗?答案是肯定的。
这是因为 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
。
我同意这令人困惑,但这就是正在发生的事情。
在这行代码中:
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>
并且您随后的方法调用被允许。