在觀察Java源碼的時候,發現了這麼一個寫法T extends Comparable<? super T>。不由納悶爲何要這麼寫呢?有什麼好處嗎,extends和super在這裏的做用着實讓人有點不清楚。java
接下來,我將結合代碼跟你們分享一下我關於這裏泛型應用的見解。安全
1. <T extends Comparable<? super T>>表明什麼意思app
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;就會報錯這樣就限制了上限 } }
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; // 編譯正確 } }
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); } }
上面的代碼包括三個類:
Animal
實現了Comparable<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)); // 建立一個 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>這樣的參數。
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 的靈活性。總的來講,在保證類型安全的前提下,要使用限制最少的類型參數。