java 泛型詳解


1、定義:泛型的本質是參數化類型,就是將類型由原來的具體的類型參數化,這種參數類型可以用在類、接口、方法中,分別稱為泛型類、泛型接口、泛型方法;

2、泛型類:泛型類的聲明和非泛型類的聲明類似,除了在類名后面添加了類型參數聲明部分,最典型的就是各種容器類,List、Set、Map;

public class Test<T>{
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

 a、泛型的類型參數只能是引用型類型<Integer>、<Double>(包括自定義類)等,不能是原始類型<int>、<double>等;

 b、實例化泛型類時,必須指定 T 的具體類型; 

 c、參數化類型 T 可以寫成任意字符,常用的 T 、E、K、V等表示泛型;

3、泛型接口:泛型接口與泛型類的定義及使用基本相同;

 a、實現泛型接口的類未傳入泛型實參時,在聲明此類的時候,需將泛型的聲明也加到類中;

class B<T> implements Test<T>{
     @Override
     public T next() {
         return null;
     }

b、實現泛型接口的類傳入泛型實參時,需將所有使用泛型的地方都要換成實參類型;

public class B implements Test<String> {

    private String[] strs= new String[]{"a", "b", "c"};

    @Override
    public String next() {
        return null;
    }
}

4、泛型方法:調用方法的時候,指明泛型的具體類型;

// 泛型類
class Box<T> {
    /**
     * 在泛型類中聲明了一個泛型方法,使用泛型E,這種泛型E可以為任意類型,可以類型與T相同,也可以不同。
     * 由於泛型方法在聲明的時候會聲明泛型<E>,因此即使在泛型類中並未聲明泛型,編譯器也能夠正確識別泛型方法中識別的泛型。
     */
    public <E> void B_1(E t) {
        System.out.println(t.toString());
    }

    /**
     * 在泛型類中聲明了一個泛型方法,使用泛型T,注意這個T是一種全新的類型,可以與泛型類中聲明的T不是同一種類型。
     *
     */
    public <T> void B_2(T t) {
        System.out.println(t.toString());
    }

    // 不是泛型方法
    public void B_3(T t){
        System.out.println(t.toString());
    }
}

a、所有泛型方法聲明都有一個類型參數聲明部分(由尖括號分隔),該類型參數聲明部分在方法返回類型之前(在上面例子中的<E>、<T>);

 b、只有聲明了<T>、<E>的方法才是泛型方法(B_1、B_2),泛型類中使用泛型的成員方法不是泛型方法(B_3);

 c、<T>、<E>表明該方法將使用泛型類型T、E,此時才可以在方法中使用泛型類型T、E;

 d、泛型方法體的聲明和其他方法一樣,只能是引用型類型,不能是原始類型(int、double,char等);

5、泛型上下邊界:在使用泛型的時候,我們還可以為傳入的泛型類型實參進行上下邊界的限制,類型實參只准傳入某種類型的父類或某種類型的子類;為泛型添加上邊界,即傳入的類型實參必須是指定類型的子類型;比如:

List<? extends Animal>, 通配符的上限,不能往里存,只能往外取,因為編譯器只知道容器里的是父類或者父類的子類,但不知道它具體是什么類型,所以存的時候,無法判斷是否要存入的數據的類型與容器種的類型一致,所以會拒絕set操作

<? super E>通配符的下限,往外取只能賦值給Object變量,不影響往里存因為編譯器只知道它是子類或者它的父類,這樣實際上是放松了類型限制,父類一直到Object類型的對象都可以往里存,但是取的時候,就只能當成Object對象使用了

// 泛型類
class Box<T extends Number> {
    private T t;
    public Box(T t){
        this.t = t;
    }
    public T getT(){
        return t;
    }
}
// Integer類型是Number類型的子類————正確
Box<Integer> b = new Box<Integer>(1000);
// String類型不是Number類型的子類————錯誤
Box<String> s = new Box<String>("1000");

6、類型通配符:一般是使用 ?代替具體的類型參數,?是類型實參,和Integer、Number一樣都是一種實際的類型,?可以看成所有的類型的父類(List<?> 在邏輯上是List<String>,List<Integer> 等所有List<具體類型實參>的父類);

public static void main(String[] args) {
    Box b = new Box();
    List<String> sLst = new ArrayList<String>();
    sLst.add("100");
    List<Integer> iLst = new ArrayList<Integer>();
    iLst.add(100);
    List<Number> nLst = new ArrayList<Number>();
    nLst.add(1000);
    b.BPrint(sLst);
    b.BPrint(iLst);
    b.BPrint(nLst);
}

/**
 * <? extends T>表示該通配符所代表的類型是T類型的子類
 * <? super T>表示該通配符所代表的類型是T類型的父類
 */
class Box {
    public void BPrint(List<?> lst) {
        System.out.println(lst);
    }
}

 


免責聲明!

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



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