深入理解Java 泛型原理和使用場景

泛型是什麼

泛型即參數化類型,就是將原來的具體的類型參數化。就像方法變量參數,類型也定義成類型參數,在傳入和調用的時候傳入具體的類型。看看下面的例子,有沒有什麼問題?

    List arrayList = new ArrayList();
        arrayList.add("hello");
        arrayList.add(1);
       for (int i = 0; i<arrayList.size();i++) {
           System.out.println((String)arrayList.get(i));
       }

ArrayList 可以存放任意類的值,上面的代碼中有Integer、String兩種類型,因爲沒有做參數類型限制,但是取出來當String類型使用的時候就會在運行時報錯:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

如果應用泛型,執行ArrayList類型爲String,List<String> arrayList = new ArraryList();可以在編譯階段就能發現錯誤,保證程序的健壯性。

泛型的使用

接下來我們從泛型類、泛型接口、泛型方法、泛型的通配符4個方面的介紹泛型的使用

泛型類

public class DataProcessor<T> {
    T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

泛型類還是很簡單的,只要在類名後面加上類型參數即可,類型參數可以用任意的字母代替,常用的可以是T,E,K,V。在使用的時候只要傳入想要的具體的參數:

DataProcessor<String> data = new DataProcessor();

泛型接口

//定義一個泛型接口
public interface Generator<T> {
    public T next();
}

這裏泛型接口有2點需要注意的點;

  • 泛型接口沒有傳入泛型實參時,泛型接口的實現類也在定義時,也必須也泛型接口一樣將類型參數加到類中:
class FruitGenerator<T> implements Generator<T>{
    @Override
    public T next() {
        return null;
    }
}
  • 泛型接口傳入具體的泛型實參,泛型接口的實現類也用到泛型的地方需要加上具體的類型如下:
class DataHolder implements Generator<String>{
    @Override
    public String next() {
    	return null;
    }
}

泛型方法

首先泛型的方法是可以存在泛型類中,也是可以存在普通類中的,記住:能用泛型方法可以解決的問題,儘量使用泛型方法,下面用一個例子介紹泛型方法的使用:

class DataHolder<T>{
    T item;
    
    public void setData(T t) {
    	this.item=t;
    }
    
    public T getData() {
    	return this.item;
    }
    
    /**
     * 泛型方法
     * @param e
     */
    public <E> void PrinterInfo(E e) {
    	System.out.println(e);
    }
}

上面的例子中泛型類的類型參數T和泛型方法類型參數E,是沒有任何關係的。甚至都可以用T代替。PrinterInfo 的泛型方法的參數可以的String,Integer。泛型方法注意的幾點:

  • public與返回值中間的<T>非常重要,可以理解爲聲明此方法爲泛型方法。
  • 與泛型類的定義一樣,此處T可以隨便寫爲任意標識,常見的如T、E、K、V等形式的參數常用於表示泛型。

 

泛型上下邊界通配符

在使用泛型的時候,我們還可以爲傳入的泛型類型實參進行上下邊界的限制,如:類型實參只准傳入某種類型的父類或某種類型的子類

  • 爲泛型添加上邊界,即傳入的類型實參必須是指定類型的子類型
public class DataProcessor<T extends Number> {

    T data;

    public T getData() {
        return data;
    }

    public DataProcessor(T data) {
        this.data = data;
    }

    public void setData(T data) {
        this.data = data;
    }


}

        DataProcessor<Integer> d2 = new DataProcessor<>(12);
        
        //這一行代碼編譯器會提示錯誤,因爲String類型並不是Number類型的子類
        DataProcessor<String> d1 = new DataProcessor<String>("hello");

在來一個泛型參數的例子:

 private <T extends Number> T show (DataProcessor<T> dataProcessor) {

        System.out.println("container key :" + dataProcessor.getData());
        T test = dataProcessor.data;
        return test;

    }

在泛型方法中添加上下邊界限制的時候,必須在權限聲明與返回值之間的<T>(或者是其它任意類型)上添加上下邊界,即在泛型聲明的時候添加.

總結

相信大家日常工作中肯定是經常用到泛型,尤其是集合的使用。有時候也會自定泛型來簡化代碼,一句話就是能用泛型就儘量用泛型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章