此代码
static void writeTo(List<? super Apple> apples) {
apples.add(new Apple());
apples.add(new Jonathan());
}
此代码的作者声明
参数apples是某种类型的List,它是Apple的基本类型;因此,您知道添加Apple或Apple的子类型是安全的。由于下限是Apple,
Jonathan是Apple的子类。
但是当我尝试这个时
List<Jonathan> loj = new ArrayList<Jonathan>();
listSuper(loj);
它给了我这个错误
The method listSuper(List<? super Apple>) in the type Basket<T> is not applicable for the arguments (List<Jonathan>)
listSuper
看起来像这样
static void listSuper (List<? super Apple> cont) {}
两者有何不同?
还有什么让我对我发布的第一个代码感到困惑 我想 ? super T意味着T的任何基类型,但从它的外观来看,他添加了T的子类型。我很困惑。
答案 0 :(得分:5)
List<? super Apple>
表示List
您可以添加Apple
(并且Jonathan
是 Apple
,您可以将Jonathan
放入该类型的List
中。
它可以是List<Apple>
,List<Fruit>
或List<Object>
,但不能List<Jonathan>
,因为您无法将Apple
个List<Jonathan>
放入?
。如您所见,在这种情况下,Apple
可以是List<? extends Apple>
或其任何超类。
List
表示Apple
您可以获得List<Apple>
。它可以是List<Jonathan>
或List<Fruit>
,但不能是List<Fruit>
,因为Apple
不能保证仅包含extends
。
此解释称为“producer - super
,consumer - super
”规则:如果参数充当元素的使用者,则应使用{{1}}声明,反之亦然
答案 1 :(得分:4)
Jonathan
是Apple
的子类型,而不是超类型。它匹配<? extends Apple>
但不匹配<? super Apple>
答案 2 :(得分:0)
代码的作者错了。你不能将Apple的子类传递给一个方法吗?超级苹果,只有苹果本身和超级苹果。如果你想能够添加Apple的子类,你需要使用?延伸Apple。
答案 3 :(得分:0)
type参数必须是Apple的超类型,而不是子类,这是Jonathan
。所以,例如,这是有效的:
List<Fruit> loj = new ArrayList<Fruit>();
listSuper(loj);
答案 4 :(得分:0)
两者有何不同?
另外,我发布的第一个代码让我感到困惑的是我 想?超级T意味着任何基本类型的T.但从外观上看 它添加了T的子类型。我很困惑。
您必须区分(1)您可以插入到通用列表中的内容和(2)可以作为参数发送到具有泛型列表参数的方法的内容。
您可以将Apple
的子类型插入apples
,因为绑定的类型参数是一个能够引用其所有子类型的基类。
如果Jonathan
不是Apple
的超级类型,那么尝试向该方法发送Jonathan
列表通常是不正确的,因为我会允许将Apple
插入Jonathan
列表中。然后,您将获得类型Jonathan
的引用,访问它不知道的对象的属性和方法,这不是类型安全的。