1

这段代码

static void writeTo(List<? super Apple> apples) {
        apples.add(new Apple());
        apples.add(new Jonathan());
    }

这段代码的作者说

参数 apples 是某种类型的 List,它是 Apple 的基本类型;因此您知道添加 Apple 或 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 的子类型。我很困惑。

4

5 回答 5

6

List<? super Apple>表示 aList你可以添加Apple到(因为Jonathan 是 a Apple,你也可以将Jonathans 放入List该类型的 a 中)。

它可以是List<Apple>,List<Fruit>List<Object>, 但不是List<Jonathan>, 因为你不能将任意Apples 放入List<Jonathan>. 如您所见,在这种情况下?可以是一个Apple或任何它的超类。

List<? extends Apple>意味着List你可以从中得到一个Apple。它可以是List<Apple>or List<Jonathan>,但不是List<Fruit>,因为List<Fruit>不能保证只包含Apples。

这种解释被称为“生产者- extends,消费者- super”规则:如果参数充当元素的消费者,则应使用 声明super,反之亦然。

于 2012-09-06T14:05:21.093 回答
4

Jonathan是 的子类型Apple,而不是超类型。它会匹配<? extends Apple>但不匹配<? super Apple>

于 2012-09-06T14:04:29.520 回答
0

代码的作者是错误的。您不能将 Apple 的子类传递给采用 ? 超级苹果,只有苹果本身和苹果的超类。如果您希望能够添加 Apple 的子类,您需要使用 ? 扩展苹果。

于 2012-09-06T14:04:07.010 回答
0

type 参数必须是 Apple 的超类型,而不是子类,这是什么Jonathan。因此,例如,这将是有效的:

List<Fruit> loj = new ArrayList<Fruit>();     
listSuper(loj); 
于 2012-09-06T14:05:54.853 回答
0

两者有何不同?

还有什么让我对我发布的第一个代码感到困惑的是我认为?super T 表示 T 的任何基本类型。但从外观上看,他添加了 T 的子类型。我很困惑。

您必须区分 (1) 可以插入通用列表的内容和 (2) 可以作为参数发送到具有通用列表参数的方法的内容。

  1. 您可以插入 的子类型,Apple因为apples绑定类型参数是一个能够引用其所有子类型的基类。

  2. 如果Jonathan不是 的超类型Apple,那么尝试将列表发送Jonathan到该方法通常是不正确的,因为我可以将Apples 插入到 s 列表中Jonathan。然后你会有类型的引用Jonathan访问它一无所知的对象的属性和方法,这不是类型安全的。

于 2012-09-06T14:11:04.623 回答