当 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>并且您随后的方法调用被允许。