你瞭解泛型嘛

泛型

爲什麼要有泛型?

集合容器類在設計階段/聲明階段不能確定這個容器到底實際存的是什麼類型的對象,
所以在JDK1.5之前只能把元素類型設計爲Object,JDK1.5之後使用泛型來解決。
因爲這個時候除了元素的類型不確定,其他的部分是確定的,例如關於這個元素如何
保存,如何管理等是確定的,因此此時把元素的類設計成一個參數,這個類型參數
叫做泛型。

在這裏插入圖片描述

什麼是泛型

所謂泛型,就是允許在定義類、接口時通過一個標識表示類中某個屬性的類
型或者是某個方法的返回值及參數類型。這個類型參數將在使用時( 例如,
繼承或實現這個接口,用這個類型聲明變量、創建對象時)確定(即傳入實
際的類型參數,也稱爲類型實參)。Collection<E>, List<E>, 
ArrayList<E> 這個<E>就是類型參數,即泛型。

泛型類

class Myclass<T> {
//T代表類型參數,指代任何類型(不包括基本類型8種,要使用其包裝類),常用單個大寫字母表示,
    private T t;
}
public class Test1 {
    public static void main(String[] args) {
        Myclass<String> myclass1=new Myclass<String>();
        Myclass<Integer> myclass2=new Myclass<Integer>();
    }
}
  • 泛型類可以接受多個類型參數
class Mclass<T,E> {
    private T t;
    private E e;
}
public class Test1 {
    public static void main(String[] args) {
        Mclass<String,Integer> mclass=new Mclass<String, Integer>();
    }
}
  • 引入泛型後,一個泛型類的類型在使用時已經確定好,因此無需向下轉型

泛型類的使用-通配符(Wildcards)

? 用於在泛型的使用,即爲通配符
public class MyArrayList<E> {...}
// 可以傳入任意類型的 MyArrayList
public static void printAll(MyArrayList<?> list) {
...
} /
/ 以下調用都是正確的
printAll(new MyArrayList<String>());
printAll(new MyArrayList<Integer>());
printAll(new MyArrayList<Double>());
printAll(new MyArrayList<Number>());
printAll(new MyArrayList<Object>());
  • 通配符-上界
<? extends 上界>
// 可以傳入類型實參是 Number 子類的任意類型的 MyArrayList
public static void printAll(MyArrayList<? extends Number> list) {
...
}
  • 通配符-下界
<? super 下界>
// 可以傳入類型實參是 Integer 父類的任意類型的 MyArrayList
public static void printAll(MyArrayList<? super Integer> list) {
...
}

泛型方法

在方法聲明時用<T>表示的方法,<T>中的T稱爲類型參數,而方法中的T被稱爲參數
化類型,他不是運行時真正的參數
public <T> void fun(T t) {
        System.out.println(t);
    }
     public <T> T test(T t) { //<T>泛型方法的定義,表示該方法爲泛型方法。第二個T表示返回類型是T,第三個T表示參數類型是T.
        return t;//類型參數也可以做返回值
    }
  • 當泛型類與泛型方法共存時,泛型方法始終與自己定義的類型爲準、定義時讓泛型類和泛型方法的類型不同名,來避免混淆
class Myclass2<T> {
    public <T> T func(T t) {
        return t;
    }
}
public class Test1 {
    public static void main(String[] args) {
        Myclass2<String> myclass2=new Myclass2<>();
        System.out.println(myclass2.func(12));
        System.out.println(myclass2.func("123"));
    }
}

泛型接口

interface ISubject<T> {
    void fun(T t);
    
}
  • 子類在實現接口時有兩種實現方式
    1)此時子類實現接口時就確定類型
class SujectImpl implements ISubject<String> {
    @Override
    public void fun(String s) {

    }
}

2)子類實現接口時仍然保留泛型

class SubjectImpl2<T> implements ISubject<T> {
    @Override
    public void fun(T t) {

    }
}

類型擦除、

泛型是作用在編譯期間的一種機制,實際上運行期間是沒有這麼多類的,那運行期間
是什麼類型呢?這裏就是類型擦除在做的事情

jdk 1.5引入 泛型只存在於編譯階段,在進入JVM之前,與泛型有關的信息會被完全擦除 泛型類再進行類型擦除時,未指定泛型的上限,泛型相關信息會被擦除位Object類型,如果有上限,擦除爲對應類型的上限。

class Myclass<T,E extends Number> {
      public T t;
      public E e;
}
T>>>Object
E>>>Number

泛型的注意點

  1. 泛型類型參數不支持基本數據類型
  2. 無法實例化泛型類型的對象
  3. 無法使用泛型類型聲明靜態的屬性
  4. 無法使用 instanceof 判斷帶類型參數的泛型類型
  5. 無法創建泛型類數組
  6. 無法 create、catch、throw 一個泛型類異常(異常不支持泛型)
  7. 泛型類型不是形參一部分,無法重載
  8. 泛型代碼與JVM ① 虛擬機中沒有泛型,只有普通類和方法。 ② 在編譯階段,所有泛型類的類型參數都會被Object或者它們的限定邊界來替換。(類型擦除) ③ 在繼承泛型類型的時候,橋方法的合成是爲了避免類型變量擦除所帶來的多態災難。 無論我們如何定義一個泛型類型,相應的都會有一個原始類型被自動提供。原始類型的名字就是擦除類型參數的泛型類型的名字。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章