Java Generics中'super'和'extends'之间的区别是什么?

ben*_*hsu 78 java generics

我正在尝试学习Java泛型.我不清楚你什么时候使用<T extends Foo>以及何时使用<T super Foo>.这些事情中的每一个对T意味着什么?可以说我有<T extends Comparable><T super Comparable>,什么每个这些是什么意思?

我在sun.com上看过几个教程,但我还是迷路了.有人能举例说明吗?

谢谢!

R S*_*hko 270

它取决于它允许的继承层次结构的方式.假设你有一个继承自"祖父母"继承自"父母"的班级"孩子".

<T extends Parent>接受父母或子女,同时<T super Parent>接受父母或祖父母.

  • 这是我见过的这个问题的最佳答案,也应该是公认的答案.简单而且完美. (23认同)
  • 所以它更像是继承(扩展)或继承(超级) (4认同)

Ivo*_*cky 15

通配符有三种类型:

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

  • 仅供参考:这是从http://java.sun.com/developer/technicalArticles/J2SE/generics/中提取的.将来请提及您的来源而不是写作,就好像它们是您的. (23认同)

whi*_*rra 15

请参阅Effective Java 2nd Edition,Item 28:

佩奇

P roducer ë xtends,Ç onsumer 小号 UPER

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

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

  • 这并没有真正解释它们是如何工作的或它们的意思,而[R Samuel Klatchko的回答](http://stackoverflow.com/a/1911036/254477)确实如此. (54认同)
  • 不明白,不解释差异. (9认同)
  • 这就是Bloch解释它的方式:_假设你想要添加批量方法to``Stack <E>`:•`void pushAll(Collection <?extends E> src);`•`void popAll(Collection <?super E> dst) ;`•_User can_` pushAll` _ from a_`C集<Long>`_或a_`集合<Number>`_onto a_`Stack <Number>`•_User can_`popA​​ll`_into a_`C集<Object>`_或a_`集合<Number>`_ from a_`Stack <Number>` (9认同)
  • 制片人?消费者?请解释。你没有回答问题。 (2认同)
  • 很高兴您喜欢引用《Effective Java 2nd Edition》,但作者已经提到他已经四处搜索过,这意味着他已经看到了这一点。不管怎样,他的问题不是何时使用 super 和 extends,而是它们的实际含义。这意味着他正在寻找两者之间的机械差异,以了解“为什么”使用而不是“何时”使用。这个答案充其量是离题的,但我认为它与问题完全无关。 (2认同)

Sta*_*los 13

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

无论何时打算写入列表,都要使用List <T super Suit> .

当您将一个Object放入List时,您所关心的只是该对象的类型与列表所拥有的类型兼容.因此,您希望列表采用该对象的类型或该对象的任何超类.

无论何时打算从列表中读取,都要使用List <T extends Suit> .

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


Ale*_*yak 5

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

public class MyClass< T extends Closeable & Runnable >
{
  // Closeable and Runnable are chosen for demonstration purposes only
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果您看到MyClass< ConcreteT >那么 ConcreteT 必须声明为

public class ConcreteT
  implements Closeable, Runnable
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

对于有界通配符,请阅读这篇文章。阅读有关get-put 原理的部分。基本上,super对应write语义,extends对应read语义。