<T extends Comparable<T>>表明T实现了Comaprable<T>接口,此条件强制约束,泛型对象必须直接实现Comparable<T>(所谓直接就是指不能通过继承或其他方式)
<T extends Comparable<? super T>> 表明T的任意一个父类实现了Comparable<? super T>接口,其中? super T表示 ?泛型类型是T的父类(当然包含T),因此包含上面的限制条件,且此集合包含的范围更广
Java 中类似 <T extends Comparable<? super T>>
这样的类型参数 (Type Parameter) 在 JDK 中或工具类方法中经常能看到。比如 java.util.Collections
类中的这个方法声明:
public static <T extends Comparable<? super T>> void sort(List<T> list)
我知道 extends
和 super
这样的关键字在泛型中是干什么的,但对上面这样复杂的类型参数声明着实有点看不懂。
我觉得类型参数 T 写成这样就足够了:
<T extends Comparable<T>>
可 T 偏偏被声明成这样:
<T extends Comparable<? super T>>
搞这么复杂图啥呢?难道 Java 只是高智商人士的玩具?
平常写工具类的机会比较少,上面的方法参数类型看不懂或写不出来问题倒也不大。只要知道怎么调用这些方法,日子就能混过去。我估计像我这样混日子的程序员不少吧。
终于有一天,我觉得有点对不起 Java Developer 这个头衔了,于是认真看了看书,认真 Google 了一下,终于搞明白了这样的类型参数是怎么回事儿。
1 <T extends Comparable<T>>
和 <T extends Comparable<? super T>>
有什么不同
-
类型 T 必须实现
Comparable
接口,并且这个接口的类型是 T。只有这样,T 的实例之间才能相互比较大小。例如, 在实际调用时若使用的具体类是 Dog,那么 Dog 必须implements Comparable<Dog>
-
类型 T 必须实现
Comparable
接口,并且这个接口的类型是 T 或 T 的任一父类。这样声明后,T 的实例之间,T 的实例和它的父类的实例之间,可以相互比较大小。例如, 在实际调用时若使用的具体类是 Dog (假设 Dog 有一个父类 Animal),Dog 可以从 Animal 那里继承Comparable<Animal>
,或者自己implements Comparable<Dog>
。
<T extends Comparable<T>>
<T extends Comparable<? super T>>
2 我对 <T extends Comparable<? super T>>
类型参数的理解
光看上面的定义除了摸不着头脑,不会有其它感觉。下面用代码来说明为什么要这样声明。
2.1 代码运行环境
我使用的 JDK 版本是: 1.8.0_60
,在 Eclipse 中编译运行。因为注释用了中文,编码采用 UTF-8。如果你要在命令行下编译、运行,编译时要使用 -encoding UTF-8
选项:
javac -encoding UTF-8 TypeParameterTest.java
另外,Eclipse 中的警告、错误信息跟命令行中的不一样(个人感觉 Eclipse 中的信息要好懂一些)。以下的示例以 Eclipse 中的信息为准。
2.2 示例代码
1: package generics3;
2:
3: import java.util.ArrayList;
4: import java.util.Collections;
5: import java.util.List;
6:
7: public class TypeParameterTest
8: {
9: //第一种声明:简单,灵活性低
10: public static <T extends Comparable<T>> void mySort1(List<T> list)
11: {
12: Collections.sort(list);
13: }
14:
15: //第二种声明:复杂,灵活性高
16: public static <T extends Comparable<? super T>> void mySort2(List<T> list)
17: {
18: Collections.sort(list);
19: }
20:
21: public static void main(String[] args)
22: {
23: