Java泛型中的“超级”和“扩展”有啥区别[重复]

Posted

技术标签:

【中文标题】Java泛型中的“超级”和“扩展”有啥区别[重复]【英文标题】:What is the difference between 'super' and 'extends' in Java Generics [duplicate]Java泛型中的“超级”和“扩展”有什么区别[重复] 【发布时间】:2010-12-27 00:32:37 【问题描述】:

我正在尝试学习 Java 泛型。我不清楚你什么时候使用<T extends Foo>,什么时候使用<T super Foo>。这些事情中的每一件事对 T 意味着什么?假设我有<T extends Comparable><T super Comparable>,它们分别是什么意思?

我在 sun.com 上阅读了几篇教程,但我仍然迷路。有人可以举例说明吗?

【问题讨论】:

这个问题之前已经讨论过了 - 见***.com/questions/1368166/…和***.com/questions/252055/java-generics-wildcards和***.com/questions/1906677/… (注意Comparable 是一个泛型类型,所以在泛型绑定中使用它作为原始类型会导致痛苦。它应该,最“简单”是Comparable<?>。)跨度> 没有“”,只有“ superwhatever>” 【参考方案1】:

这取决于它允许的继承层次结构。假设你有一个继承自“祖父母”的“父母”的“孩子”类。

<T extends Parent> 接受 Parent 或 Child,而 <T super Parent> 接受 Parent 或 Grandparent。

【讨论】:

这是我见过的这个问题的最佳答案,应该是公认的答案。简单而完美。 所以它更像是向下继承(扩展)或向上继承(超级) 接受 Parent 或 Grandparent,但是 Child 呢?我只是尝试添加,它接受了 "<T super Parent> 接受父母或祖父母" - 和Object,对吗?【参考方案2】:

通配符分为三种:

? extends Type:表示Type 类型的子类型族。这是最有用的通配符。 ? super Type:表示Type 类型的超类型族。 ?:表示所有类型或任何类型的集合。

【讨论】:

仅供参考:这是从java.sun.com/developer/technicalArticles/J2SE/generics 中提取的,以后请提及您的来源,而不是写得好像它们是您的一样。 @BalusC 的文章链接不再有效。这是当前的一个:oracle.com/technetwork/articles/javase/generics-136597.html【参考方案3】:

参见 Effective Java 第 2 版,第 28 条:

PECS

P生产者extends,C消费者s上层

如果你的参数是生产者,它应该是<? extends T>,如果是消费者,它必须是<? super T>

看看 Google Collections,他们知道如何使用它,因为他们有 Bloch ;)

【讨论】:

这并不能真正解释它们的工作原理或含义,而 R Samuel Klatchko's answer 可以。 不明白,不解释区别。 Bloch 是这样解释的:假设你想将批量方法添加到 Stack<E>: •void pushAll(Collection<? extends E> src);void popAll(Collection<? super E> dst);用户可以 i> pushAll 从一个 Collection<Long> 或一个 Collection<Number> 到一个 Stack<Number>用户可以 popAll 进入一个 Collection<Object> 或一个 Collection<Number> 来自一个 Stack<Number> 制片人?消费者?请解释。你没有回答问题。 很高兴你喜欢引用 Effective Java 2nd Edition,但作者已经提到他已经搜索过,暗示他已经看到了。无论如何,他的问题不是何时使用 super vs extends,而是它们的实际含义。这意味着他正在寻找两者之间的机械差异,以了解“为什么”使用而不是“何时”使用。这个答案充其量是切题的,但我认为它与问题完全无关。【参考方案4】:

当我阅读鲍勃叔叔的文章时,对我来说最好的答案来自@BSingh。我在这里继续,文章的结论。

使用列表super Suit> 每当您要写入 到列表中。

当您将一个对象放入列表时,您所关心的只是该对象的类型是否与列表所包含的类型兼容。因此,您希望列表采用该对象的类型或该对象的任何超类。

使用列表extends Suit> 每当您要从列表中读取

另一方面,当您从列表中读取数据时,您希望正在读取的类型是列表中包含的类型,或者是该类型的派生类型。

【讨论】:

【参考方案5】:

如果您询问类型参数,那么 Java 中没有 <T super X> 构造。有界参数只能extend,但可以扩展多个类型。例如

public class MyClass< T extends Closeable & Runnable >

  // Closeable and Runnable are chosen for demonstration purposes only

在这种情况下,如果您看到MyClass&lt; ConcreteT &gt;,则必须将 ConcreteT 声明为

public class ConcreteT
  implements Closeable, Runnable

   ...

对于有界通配符,请阅读this article。阅读get-put 原则部分。基本上super对应write语义,extends对应read语义。

【讨论】:

【参考方案6】:

记住 PECS - 生产者扩展消费者支持。此外,鲍勃叔叔在他的工匠系列中对此进行了很好的讨论。查看http://objectmentor.com/resources/articles/The_Craftsman_44__Brown_Bag_I.pdf

【讨论】:

以上是关于Java泛型中的“超级”和“扩展”有啥区别[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Java泛型中extends和super的区别

如何在 C# 的泛型中使用扩展

java 泛型中 TE ... 和 问号(通配符)的区别

java泛型中的上下界通配符

java中E,T,?的区别?

java泛型中extends 和 super的区别