[转载]Java泛型的应用——T extends Comparable<? super T>
</h1>
<div class="clear"></div>
<div class="postBody">
<div class="">
</h1>
<div class="clear"></div>
<div class="postBody">
<div class="">
在观察Java源码的时候,发现了这么一个写法T extends Comparable<? super T>。不禁纳闷为什么要这么写呢?有什么好处吗,extends和super在这里的作用着实让人有点不清楚。
接下来,我将结合代码跟大家分享一下我关于这里泛型应用的看法。
1. <T extends Comparable<? super T>>代表什么意思
- 大家可以明白的是这里应用到了Java的泛型,那么首先向大家说明一下这里extends的作用
extends后面跟的类型,如<任意字符 extends 类/接口>表示泛型的上限。示例代码如下:
import java.util.*; class Demo<T extends List>{} public class Test { public static void main(String[] args) { Demo<ArrayList> p = null; // 编译正确 //这里因为ArrayList是List的子类所以通过 //如果改为Demo<Collection> p = null;就会报错这样就限制了上限 } }
- 在理解了extends所表示的泛型的上限后,接下来介绍一下super的作用,它与extends相反,表示的是泛型的下限。
- 所以结合上述两点,我们来分析一下这句话整体代表什么意思。首先,extends对泛型上限进行了限制即T必须是Comparable<? super T>的子类,然后<? super T>表示Comparable<>中的类型下限为T!
2. <T extends Comparable<T>>
和 <T extends Comparable<? super T>>
有什么不同
接下来我们通过对比,使得大家对为何要这样编写代码有更加深刻的印象。
<T extends Comparable<T>>
它代表的意思是:类型T必须实现Comparable
接口,并且这个接口的类型是T。这样,T的实例之间才能相互比较大小。这边我们以Java中GregorianCalendar这个类为例。
代码如下所示:
import java.util.GregorianCalendar; class Demo<T extends Comparable<T>>{} //注意这里是没有? super的 public class Test { public static void main(String[] args) { Demo<GregorianCalendar> p = null; } }
这里编译报错,因为这里的<T extends Comparable<T>>相当于<GregorianCalendar extends Comparable<GregorianCalendar>>,但是GregorianCalendar中并没有实现Comparable<GregorianCalendar>,而是仅仅持有从Calendar继承过来的Comparable<Calendar>,这样就会因为不在限制范围内而报错。
<T extends Comparable<? super T>>
它代表的意思是:类型T必须实现Comparable
接口,并且这个接口的类型是T或者是T的任一父类。这样声明后,T的实例之间和T的父类的实例之间可以相互比较大小。同样还是以GregorianCalendar为例。代码如下所示:
import java.util.GregorianCalendar;class Demo<T extends Comparable<? super T>>{}
public class Test1
{
public static void main(String[] args) {
Demo<GregorianCalendar> p = null; // 编译正确
}
}
import java.util.ArrayList; import java.util.Collections; import java.util.List;public class Test
{
//第一种声明:简单,灵活性低
public static <T extends Comparable<T>> void mySort1(List<T> list)
{
Collections.sort(list);
}</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">第二种声明:复杂,灵活性高</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <T <span style="color: rgba(0, 0, 255, 1)">extends</span> Comparable<? <span style="color: rgba(0, 0, 255, 1)">super</span> T>> <span style="color: rgba(0, 0, 255, 1)">void</span> mySort2(List<T><span style="color: rgba(0, 0, 0, 1)"> l) { Collections.sort(list); } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">主函数中将分别创建Animal和Dog两个序列,然后调用排序方法对其进行测试<br> //main函数中具体的两个版本代码将在下面具体展示<br></span>
}
}class Animal implements Comparable<Animal>
{
protected int age;</span><span style="color: rgba(0, 0, 255, 1)">public</span> Animal(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> age) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.age =<span style="color: rgba(0, 0, 0, 1)"> age; } </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">使用年龄与另一实例比较大小</span>
@Override
public int compareTo(Animal other)
{
return this.age - other.age;
}
}class Dog extends Animal
{
public Dog(int age)
{
super(age);
}
}
上面的代码包括三个类:
Animal
实现了Comparable<Animal>
接口,通过年龄来比较实例的大小- Dog从Animal继承,为其子类。
Test
类中提供了两个排序方法和测试用的main()
方法:mySort1()
使用<T extends Comparable<T>>
类型参数mySort2()
使用<T extends Comparable<? super T>>
类型参数main()
测试方法。在这里将分别创建Animal和Dog两个序列,然后调用排序方法对其进行测试。
3.1 对mySort1()进行测试,main方法代码如下所示:
// 创建一个 Animal List List<Animal> animals = new ArrayList<Animal>(); animals.add(new Animal(25)); animals.add(new Dog(35));// 创建一个 Dog List
List<Dog> dogs = new ArrayList<Dog>();
dogs.add(new Dog(5));
dogs.add(new Dog(18));// 测试 mySort1() 方法
mySort1(animals);
mySort1(dogs);
结果编译出错,报错信息为:
The method mySort1(List<T>) in the type TypeParameterTest is not applicable for the arguments (List<Dog>)
mySort1() 方法的类型参数是<T extends Comparable<T>>,它要求的类型参数是类型为T的Comparable。
如果传入的是List<Animal>程序将正常执行,因为Animal实现了接口Comparable<Animal>。
但是,如果传入的参数是List<Dog>程序将报错,因为Dog类中没有实现接口Comparable<Dog>,它只从Animal继承了一个Comparable<Animal>接口。
注意:animals list中实际上是包含一个Dog实例的。如果碰上类似的情况(子类list不能传入到一个方法中),可以考虑把子类实例放到一个父类 list 中,避免编译错误。
3.2 对mySort12()进行测试,main方法代码如下所示:
public static void main(String[] args) { // 创建一个 Animal List List<Animal> animals = new ArrayList<Animal>(); animals.add(new Animal(25)); animals.add(new Dog(35));</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建一个 Dog List</span> List<Dog> dogs = <span style="color: rgba(0, 0, 255, 1)">new</span> ArrayList<Dog><span style="color: rgba(0, 0, 0, 1)">(); dogs.add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Dog(5<span style="color: rgba(0, 0, 0, 1)">)); dogs.add(</span><span style="color: rgba(0, 0, 255, 1)">new</span> Dog(18<span style="color: rgba(0, 0, 0, 1)">)); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 测试 mySort2() 方法</span>
mySort2(animals);
mySort2(dogs);
}
这时候我们发现该程序可以正常运行。它不但能够接受Animal implements Comparable<Animal>这样的参数,也可以接收:Dog implements Comparable<Animal>这样的参数。
class Dog extends Animal implements Comparable<Dog> { public Dog(int age) { super(age); } }
结果程序编译报错,错误信息如下所示:
The interface Comparable cannot be implemented more than once with different arguments: Comparable<Animal> and Comparable<Dog>
意义是Dog类已经从Animal中继承了Comparable该接口,无法再实现一个Comparable。
若子类需要使用自己的比较方法,则需要重写父类的public int CompareTo(Animal other)方法。
4. 总结
对Animal/Dog这两个有父子关系的类来说:<T extends Comparable<? super T>>
可以接受List<Animal>,也可以接收 List<Dog> 。而<T extends Comparable<T>>
只可以接收 List<Animal>所以,<T extends Comparable<? super T>>这样的类型参数对所传入的参数限制更少,提高了 API 的灵活性。总的来说,在保证类型安全的前提下,要使用限制最少的类型参数。