Java泛型的应用——T extends Comparable

  在观察Java源码的时候,发现了这么一个写法T extends Comparable<? super T>。不由纳闷为何要这么写呢?有什么好处吗,extends和super在这里的做用着实让人有点不清楚。java

  接下来,我将结合代码跟你们分享一下我关于这里泛型应用的见解。安全

  

  1.  <T extends Comparable<? super T>>表明什么意思app

  • 你们能够明白的是这里应用到了Java的泛型,那么首先向你们说明一下这里extends的做用

  extends后面跟的类型,如<任意字符 extends 类/接口>表示泛型的上限。示例代码以下:ide

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这个类为例。this

  代码以下所示:spa

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>,这样就会由于不在限制范围内而报错code

  • <T extends Comparable<? super T>>  

  它表明的意思是:类型T必须实现Comparable接口,而且这个接口的类型是T或者是T的任一父类。这样声明后,T的实例之间和T的父类的实例之间能够相互比较大小。一样仍是以GregorianCalendar为例。代码以下所示:blog

import java.util.GregorianCalendar;

class Demo<T extends Comparable<? super T>>{}

public class Test1
{
    public static void main(String[] args) {
       Demo<GregorianCalendar> p = null; // 编译正确
    }
}  
  此时编译经过,这里能够理解为<GregorianCalendar extends Comparable<Calendar>>!由于Calendar为GregorianCalendar 的父类而且GregorianCalendar 实现了Comparable<Calendar>,具体能够在API中进行查看!
 
  3. 实例代码演示
  代码以下所示:
 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);
     }
 
     //第二种声明:复杂,灵活性高
     public static <T extends Comparable<? super T>> void mySort2(List<T> l)
     {
         Collections.sort(list);
     }
 
     public static void main(String[] args)
     {
         //主函数中将分别建立Animal和Dog两个序列,而后调用排序方法对其进行测试
     //main函数中具体的两个版本代码将在下面具体展现
} } class Animal implements Comparable<Animal> { protected int age; public Animal(int age) { this.age = age; } //使用年龄与另外一实例比较大小 @Override public int compareTo(Animal other) { return this.age - other.age; } } class Dog extends Animal { public Dog(int age) { super(age); } }

上面的代码包括三个类:

  1. Animal实现了Comparable<Animal>接口,经过年龄来比较实例的大小
  2. Dog从Animal继承,为其子类。
  3. 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));

    // 建立一个 Dog List
    List<Dog> dogs = new ArrayList<Dog>();
    dogs.add(new Dog(5));
    dogs.add(new Dog(18));

    // 测试  mySort2() 方法
    mySort2(animals);
    mySort2(dogs);
}

  这时候咱们发现该程序能够正常运行。它不但可以接受Animal implements Comparable<Animal>这样的参数,也能够接收:Dog implements Comparable<Animal>这样的参数。

  3.3 是否能够经过将Dog实现Comparable<Dog>来解决问题?
  由分析可得程序出现问题是由于Dog类没有实现接口Comparable<Dog>,那么咱们可否将该类实现接口Comparable<Dog>来解决问题呢?
  代码以下所示:
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 的灵活性。总的来讲,在保证类型安全的前提下,要使用限制最少的类型参数。

相关文章
相关标签/搜索