Java泛型的應用——T extends Comparable


  在觀察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; // 編譯正確
    }
}  
  此時編譯通過,這里可以理解為<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 的靈活性。總的來說,在保證類型安全的前提下,要使用限制最少的類型參數。

  

 

  

 

 

 

  

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM