Java——泛型(最易懂的方式講解泛型)

來自:
代碼大溼
代碼大溼程序員

寫在前面:

只要認真看過,基本能很熟悉泛型的特性。泛型是JDK1.5以後出現的,好比JDK1.5以前的ArrayList,會出現2個問題數組

1:向ArrayList當中添加對象,添加String和Date均可以,但咱們的本意是添加String,編譯器不會檢查錯誤,會致使不可預知的錯誤。this

2:get()方法獲得一個元素的時候要進行強制類型轉換。
因此泛型的引入很好的解決了這2個問題。.net


1,泛型類

一個泛型類以下;code

class Pair<T,E>{
    private T first;
    private E second;
    public T getFirst() {
        return first;
    }
    public void setFirst(T first) {
        this.first = first;
    }
    public E getSecond() {
        return second;
    }
    public void setSecond(E second) {
        this.second = second;
    }
    
}

尖括號中的T,E稱爲類型變量。對象


2. 泛型方法

一個泛型方法的簽名:
public static T getV(T t)
類型變量在方法修飾符的後面,返回值的前面。
blog


3.類型擦除

JVM中是不存在泛型這一說法的,即編譯器在編譯的時候,將類型變量擦除掉了,換成了Bounding Type。上面的Pair類在編譯後,Pair變成這樣了:繼承

class Pair{
    private Object first;
    private Object second;
    public Object getFirst() {
        return first;
    }
    public void setFirst(Object first) {
        this.first = first;
    }
    public Object getSecond() {
        return second;
    }
    public void setSecond(Object second) {
        this.second = second;
    }
    
}

將類型變量替代成了Object。更多的類型替代請繼續往下閱讀;ci

類型擦除帶來的問題:
定義一個Pair的子類get

class extendsPair extends Pair<Date,Date>{
    public void setSecond(Date d){
        super.setSecond(d);
        System.out.println("我是字類的方法");
    }
}

Pair pair=new extendsPair();
        pair.setSecond(new Date());

執行結果是:
我是父類的方法
我是字類的方法

爲何會是這樣呢?

由於子類本身定義了一個public void setSecond(Date d)
可是從父類繼承了一個方法是public void setSecond(Object d),這是2個不一樣的方法。當用父類的引用指向子類的實例,而後調用詞方法,對於編譯器只會尋找父類的那個方法即public void setSecond(Object d)。而程序員的意圖是調用子類的方法public void setSecond(Date d),因此此種狀況,編譯器會爲咱們生成一個橋方法

public void setSecond(Object d){
    setSecond((Date)d);
}

因此正如結果中那樣,先調用父類的setSecond方法,而後在此方法中調用子類的setSecond方法。


4.類型限定符

1.類型限定符,用關鍵字extends表示子類型限定

對於下面方法

public People getName(Pair<People,People> p){
        return p.getFirst();
    }

這個方法,咱們沒法傳入Pair<Student,Studnet>類型的參數,此時咱們就要用到子類型限定,將此方法改成:

public People getName(Pair<? extends People,? extends People> p){
        return p.getFirst();
    }

用關鍵字super表示超類型限定,<?>表示無類型限定。好比一個方法getPairs()咱們要返回Pair<>[]。其中的元素有Pair<Student>,還有Pair<Scientist>Student和Scientist不存在繼承關係。這是就只能用<?>

2:類型限定注意事項:

看下面代碼

public People getName(Pair<? extends People,? extends People> p){
        Student student=new Student();
        p.setFirst(student);
        return p.getFirst();
    }

p.setFirst(student)會報錯,由於Pair<? extends People,? extends People>的setFirst方法是

public void setFirst(<? extends People first) {
        this.first = first;
    }

形參是People的某子類,可是編譯器不能肯定Student是否是這個子類的子類。可是對於get方法,總能將返回類型轉型成People類。相應的使用超類型限定,get()方法會報錯。


5:泛型的注意事項:

1:不能在泛型類的靜態上下文中定義含有類型變量的靜態成員,如:
class Pair<T,E>{
    private static T name;
    ....

只是對於泛型類來講,如上面普通類中能夠存在靜態方法。這個緣由很簡單,好比Pair<String,String>和Pair<Date,Date>這2個對象,那麼這兩個對象要共享name,那麼變量name是什麼類型呢?存在衝突。


2:泛型類不能繼承異常類,也不能被拋出

由於泛型類不能繼承Throwable,可是類型變量能夠被拋出,如:

public static <T extends Throwable> T get(T t) throws T{
        return t;
    }

3:泛型數組是不合法的

不能建立這樣的數組:

Pair<String,String>[] pairs=new Pair<String,String>[10];

由於實際上paris是Pair[]類型的,因此咱們添加Date類型的元素,編譯器是不會發現的。這會產生難以定位的錯誤。可是咱們能夠用下面的方式來定義泛型數組。

Pair<String,String>[] pairs=(Pair<String, String>[])(new Pair[10]);
4:不能實例化類型變量

不能出現 new T(),new T[]這樣的src。由於通過類型擦除後,T均變爲BoundingType。這樣的操做沒有意義。

5:類型變量不能是raw類型。

關注更多好文:
代碼大溼
代碼大溼

相關文章
相關標籤/搜索