泛型 - 下界/上界通配符行为?
泛型(Generics)是Java中的一个重要特性,它允许我们在编写代码时使用类型参数来增加代码的灵活性和重用性。然而,在使用泛型时,我们可能会遇到一些问题,特别是在处理上限(upper bound)和下限(lower bound)通配符时。
在上面的代码示例中,我们使用了一个ArrayList来存储Number类型的对象,并将其赋值给一个通配符类型为"extends Number"的集合变量c。这意味着集合中的元素可以是任何继承自Number的类型,例如Integer、Double、Float、BigInteger等。因此,我们无法确定列表中实际存储的是哪种Number对象,因为只有特定类型的列表(如List
因此,在使用"extends Number"通配符时,我们无法向其中添加任何元素,因为它可以是上述列表中的任意一种。
与之相反的是,对于"super Number"通配符,表示集合中的每个元素都是Number的祖先类型。在这种情况下,我们可以添加任何Number的超类型或类型到集合中。使用"super Number"通配符,我们保证集合中的元素都是Number的子类或Number类型本身。
然而,我们无法确保实际类型,例如list.get(0)返回的是一个Number,但可能是一个Integer;list.get(1)返回的是一个Number,但可能是一个Float;list.get(2)返回的是一个Number,但可能是一个Double。
使用"extends"通配符用于读取操作,使用"super"通配符用于添加操作。
在Java官方文档中,有一个图示对泛型的上下界行为进行了说明,可以参考此图进行更深入的理解。
至于关于"? super Number"通配符的解释,Jon Skeet在stackoverflow上给出了一个解释。他指出,如果上界是"? super Number",那么Integer、Float和Double是不可能的。因为它们是Number的子类,而"? super Number"匹配的是超类(包括Number本身),而Number的唯一超类是Object。
最后,我们可以通过查看链接中提供的示例代码来进一步理解这些概念。
泛型 - 上界/下界通配符行为
在Java中,通配符?
表示一个"未知类型"。而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>
的情况下,为什么它可以接受任何
超类或者Object
类本身?
这就是? super Object
的含义。如果A是B的子类,你可以把B添加到A的集合中。这里也是同样的道理。
哦,这是一个打字错误。我是说你可以把A添加到B的集合中。
谢谢,我明白你的意思了。我觉得你最后一段解释得已经足够清楚了。但是在脑海中理解起来确实有些棘手。