泛型

一、泛型的概念

泛型就是:類型參數化,處理的數據類型不是固定的,而是可以作為參數傳入;
瘋狂講義定義:泛型就是允許在定義類、接口時指定類型形參,這個類型形參將在聲明變量、創建對象時確定(即傳入實際的類型參數,也可稱為類型實參);
備注:類型形參在整個接口、類體中可當成類型使用,幾乎所有可使用其他普通類型的地方都可以使用這種類型形參;也就是說在定義類、接口時使用了類型參數,在該類的方法定義和屬性定義、接口的方法定義中,這些類型形參可以被當做普通類型來用;

二、泛型類或接口

泛型類最常見的用途是作為:容器類;
Class<T>:T表示類型參數;

  • 從泛型類派生子類
    當創建了帶泛型聲明的接口、父類之后,可以為該接口創建實現類,或從該父類來派生子類;但在創建實現類或派生子類時,也就是在使用泛型類或接口時,實現的接口和子類不能再包含類型形參,應該為這個泛型類傳入一個類型實參,如果沒有傳入類型實際參數,就會引起泛型警告(泛型方法除外);
//這樣寫是錯誤的,實現的接口或父類不能再包含類型形參
public class ChildApple extends Apple<T>{
}

//正確的寫法是以下三種:在使用接口或父類時傳入類型實參或者不傳
//繼承泛型類(子類不是泛型類)
public class ChildApple extends Apple<String>{
}
//不傳時,編譯器會發出警告,系統默認把Apple<T>類中的T形參當成Object類型處理
public class ChildApple extends Apple{
}
//繼承泛型類(子類也是泛型類)
public class ChildApple<T> extends Apple<T>{
}

備注:1.方法中的形參,當調用方法時 必須 為這些形參傳入實際的數據類型;
2.類、接口中的類型形參,只有在定義類、接口時才可以使用類型形參,當使用類、接口時應為類型形參傳實際的類型,但 不是必須 傳,不傳系統默認把T形參當成Object類型;
3.創建泛型聲明的接口的實現類與創建泛型的父類幾乎一致,不在講述

  • 并不存在泛型類
Apple<String> a1 = new Apple<String>();
    
Apple<Integer> a2 = new Apple<Integer>();
    
System.out.println(a1.getClass() == a2.getClass());

上面代碼片段輸出的true,而不是false;也就說明:不管泛型類型的實際類型參數是什么,它們在運行時總有同樣的類(class);
1.泛型對其所有可能的類型參數,都具有同樣的行為,從而可以把相同的類當成許多不同的類來處理;
2.類的靜態變量和方法在所有實例間共享,所以在靜態方法、靜態初始化塊或者靜態變量的聲明和初始化中不允許使用類型參數

public class Apple<T> {
    //不能在靜態屬性聲明時使用類型形參,編譯報錯
    static T info ;
    //不能在靜態方法聲明中使用類型形參,編譯報錯
    public static void fun(T t){
    }
}

3.系統并不會真正生成泛型類,所以不能使用instanceof運算符,編譯報錯;

    //下面編譯報錯,instanceof運算符后不能使用泛型類
        if(a1 instanceof Apple<String>){
        }

4.如果Foo是Bar的一個子類型(子類或者子接口),而G是具有泛型聲明的接口或類,那么G<Foo>是G<Bar>的子類型并不成立;
5.數組和泛型有所不同,假設Foo是Bar的一個子類型(子類或者子接口),那么Foo[]依然是Bar[]的子類型;但G<Foo>不是G<Bar>的子類型;

三、泛型使用的區別
  • 1.<T extends E>:用于定義類型參數;
    它聲明一個類型參數T,可以放在泛型類定義中類名后面、泛型方法的返回值前面;
  • 2.<? extends E>:用于實例化類型參數;
    它用于實例化泛型變量中的類型參數,只是這個具體類型是未知的,只知道他是E或者E的某個子類;
四、類型通配符(?) --帶上限的通配符<? extends E>

<u>為了表示各種泛型的父類</u>,我們需要使用類型通配符,類型通配符是一個問號(?),可以將問號作為類型實參使用;
這個?被稱為通配符,它的元素類型可以匹配任何類型;
<u>可以使用A<? extends E>表示所有E泛型A的父類;問號代表未知的類型,找個未知類型總是E的一個子類(也可以是其本身);</u>

eg:List<? extends String> 可以表示為所有String泛型List的父類;
五、類型形參的上限<T extends E>
  • 1.Java泛型不僅允許在使用通配符形參時設定上限,也可以在定義類型形參時設定上限,用于表示傳給該類型形參的實際類型必須是該上限類型,或是該上限類型的子類;
  • 2.類型形參可以設定多個上限(至多有一個父類上限,也就是只能有一個extends,可以有多個接口上限)表明該類型形參必須是其父類的子類(包含父類本身),并且實現多個上限接口;
//表明T類型必須是Fruit類或其子類,并必須實現java.io.Serializable接口
public class Apple<T extends Fruit & java.io.Serializable>{
    
}

與類繼承父類、實現接口類似的是:為類型形參指定多個上限時,所有的接口上限必須位于類上限之后;也就是說,如果需要為類型形參指定類上限,類上限必須位于第一位;

六、泛型方法---- 方法修飾符 <T,S> 返回值類型 方法名(形參列表){ 方法體 }

泛型方法,就是在聲明方法時定義一個或多個類型形參;
泛型方法的格式如下:

修飾符  <T,S> 返回值類型  方法名(形參列表){
        //方法體
    }

備注:
1.泛型方法的聲明比普通方法聲明多了<u>類型形參聲明,類型形參聲明</u>以尖括號括起來,多個類型形參之間以逗號隔開,所有類型形參聲明在方法修飾符和方法返回值類型之間;
2.當方法操作的引用數據類型不確定的時候,可以將泛型定義在方法上,具體寫法如下:

public <T>  void func(T t){
    System.out.println(t.getCalss().getName());
}

3.對于static的方法而言,無法訪問泛型類上的參數類型;所以,如果static方法需要使用泛型,就必須使其成為泛型方法;
4.與接口、類聲明中定義的類型形參不同的是,方法聲明中定義的形參只能在該方法里使用,而接口、類聲明中定義的類型形參則可以在整個接口、類中使用;
泛型方法和類型通配符的區別:

  • 1.大多數時候可以使用泛型方法來代替類型通配符;
  • 2.如果方法中類型參數T只使用了一次,類型參數T的唯一效果是用來在不通的調用點傳入不通的實際類型;對于這種情況,應該使用通配符:通配符就是被設計用來支持靈活子類化的;
  • 3.泛型方法允許類型形參被用來表示方法的一個或多個參數之間的類型依賴關系,或者方法返回值與參數之間類型依賴關系。如果沒有這樣的類型依賴關系,不應該使用泛型方法;
  • 4.類型通配符與顯式聲明類型參數的一個顯著區別:類型通配符即可在方法聲明中定義形參的類型,也可以用于定義變量的類型;但泛型方法中類型形參必須在對應的方法中顯式聲明;
    public static <T,S extends T> void copy1(List<T> dest,List<S> src){
    }
    public static <T> void copy2(List<T> dest,List<? extends T> src){
    }
    //? 在寫方法簽名中定義形參的類型
    //泛型方法中的類型形參必須在對應的方法中顯式聲明
    public static <T,S> void copy(List<T> dest, List<?> src) {

    }
    //通配符用于定義變量的類型
    private List<?> list ;//代表它是各種泛型List的父類

補充:

  • 1.通配符只能出現在引用的定義中,而不能出現在創建對象中。例如:new ArrayList<?>(),這是不可以的;ArrayList<?> list = null,這是可以的。
  • 2.T extends E:只取不寫;也就是說只能獲取的值,不能去賦值;
  • 3.T super E:只寫不取,即使去取,返回的類型也只能是Object;
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • object 變量可指向任何類的實例,這讓你能夠創建可對任何數據類型進程處理的類。然而,這種方法存在幾個嚴重的問題...
    CarlDonitz閱讀 934評論 0 5
  • 開發人員在使用泛型的時候,很容易根據自己的直覺而犯一些錯誤。比如一個方法如果接收List作為形式參數,那么如果嘗試...
    時待吾閱讀 1,072評論 0 3
  • 一、泛型簡介1.引入泛型的目的 了解引入泛型的動機,就先從語法糖開始了解。 語法糖 語法糖(Syntactic S...
    Android進階與總結閱讀 1,033評論 0 9
  • 一、泛型簡介 1.引入泛型的目的 了解引入泛型的動機,就先從語法糖開始了解。 語法糖 語法糖(Syntactic ...
    Ruheng閱讀 4,635評論 2 50
  • #媽媽:可以教的數學# --- 第二講 講解數學題的次序心得 1、父母認知有上限,因此不要教孩子,父母需要做的是布...
    張茜007er閱讀 261評論 1 2