【问题标题】:Why is this such use of generic and wildcard not allowed?为什么不允许这样使用泛型和通配符?
【发布时间】:2012-09-06 13:52:55
【问题描述】:

这段代码

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

这段代码的作者声明

参数 apples 是某种类型的 List,它是 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 的子类型。我很困惑。

【问题讨论】:

  • 无法理解问题。这两个函数似乎具有相同的签名。有什么问题?
  • @vainolo 我添加了一些关于错误的信息。请检查一下

标签: java generics wildcard super


【解决方案1】:

List&lt;? super Apple&gt; 表示List,您可以将Apple 添加到(并且由于Jonathan Apple,您可以将Jonathans 放入List也是那种类型)。

它可以是List&lt;Apple&gt;List&lt;Fruit&gt;List&lt;Object&gt;,但不能是List&lt;Jonathan&gt;,因为您不能将任意Apples 放入List&lt;Jonathan&gt;。如您所见,在这种情况下,? 可以是 Apple 或其任何超类。

List&lt;? extends Apple&gt; 表示List,您可以从中获取Apple。它可以是List&lt;Apple&gt;List&lt;Jonathan&gt;,但不能是List&lt;Fruit&gt;,因为List&lt;Fruit&gt; 不能保证只包含Apples。

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

【讨论】:

  • 但是他为什么在 List 中添加了一个 Jonathan 对象?超级苹果
  • @KyelJmD:已更新。 Jonathan 是一个Apple,因此你可以把它放到一个可以包含Apples 的List 中。
【解决方案2】:

JonathanApple 的子类型,而不是超类型。它将匹配&lt;? extends Apple&gt;,但不匹配&lt;? super Apple&gt;

【讨论】:

  • 但是他为什么在苹果列表中添加了一个乔纳森?在 writeTo 方法中?
  • Jonathan的实例添加到List&lt;Apple&gt;是没有问题的,为什么会有呢?这与您尝试做的完全不同......
【解决方案3】:

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

【讨论】:

  • 您错了,请阅读最佳答案。类型列表?超级苹果可以带苹果及其所有子类型。类型列表? extends Apple 根本无法添加任何东西,但你总是从中得到苹果。
【解决方案4】:

type参数必须是Apple的supertype,而不是subclassJonathan就是这样。因此,例如,这将是有效的:

List<Fruit> loj = new ArrayList<Fruit>();     
listSuper(loj); 

【讨论】:

    【解决方案5】:

    两者有何不同?

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-27
      • 1970-01-01
      • 2011-08-17
      • 1970-01-01
      • 2010-10-04
      • 2013-09-07
      • 2010-11-01
      相关资源
      最近更新 更多