當前位置:
首頁 > 知識 > 泛型的意義和作用是啥?

泛型的意義和作用是啥?




  簡單的說,意義和作用有:


  類型的參數化,就是可以把類型像方法的參數那樣傳遞。這一點意義非凡。

  泛型使編譯器可以在編譯期間對類型進行檢查以提高類型安全,減少運行時由於對象類型不匹配引發的異常。


  泛型方法,演算法的復用。蠻神奇的。



  

想要理解為什麼引入泛型,就要知道沒有泛型的麻煩。


  我們知道現在的程序開發都是面向對象了,所以程序里會有很多各種類型的對象,對象多了肯定需要有某種類型的容器來裝。所以就有了一些容器類型,比如數組、ArrayList、HashMap、TreeSet等。

  對於數組,我們知道需要在使用時指定數組裝的對象類型,如:

Animal animal[];

Dog dog[];


  而對於集合類型容器如ArrayList、HashMap、TreeSet等,它們不但是容器,還提供了一些方法對容器內對象的操作方法,如get,set,sort。這個時候就需要知道容器內放的是什麼類型的對象,才能return或set。


  正因為程序開發人員可能把任何類型的對象放進集合容器,所以這些容器在設計的時候只能默認設計成裝Object類型對象。因為Java里Object是根類。


  所以容器就成了類似這個樣子:

public class ListContainer {

private Object obj;

public Object getObj() {

return obj;

}

public void setObj(Object obj) {

this.obj = obj;

}

}


  這樣的話,根據多態,容器就能裝任何類型的對象了。不過,取出對象時則需求進行強制類型轉換,轉換成實際的類型。但這樣會有很多類型不安全問題,為什麼呢?因為編譯器沒法幫忙做類型檢查,導致代碼在運行時易於出現ClassCastException異常。因此,類型安全問題只能由程序員自己來把關了,記住各種類型,避免類型轉換錯誤。

ListContainer myContainer = new ListContainer();

myContainer.setObj("123");

ArrayList objectList = new ArrayList();

objectList.add(myContainer);

//下面這句編譯時無異常,運行時會ClassCastException異常

Integer myStr = (Integer) ((ListContainer)objectList.get(0)).getObj();

//下面這句ok

String myStr = (String) ((ListContainer)objectList.get(0)).getObj();


  

泛型出場:類型的參數化


  利用泛型,重新設計:

public class ListContainer {

private T t;

public T getObj() {

return t;

}

public void setObj(T t) {

this.t= t;

}

}


  這裡的T的類型的參數,具體T指代什麼類型,是String還是Animal還是Dog類型此處不管,而在程序員開發時使用到ListContainer時再指定,如:

ListContainer myCon=new ListContainer();


  這種環境下,編譯器就知道ListContainer容器是放Dog類型對象的。並進行類型安全檢查。

myCon.setObj(new Dog())//ok

myCon.setObj(「123」);//編譯時提醒類型錯誤


  這樣設計的容器在使用時編譯器就可以幫忙做很大一部分的類型安全檢查工作了,這就避免了很多運行時的ClassCastException異常,程序員也無需記住各種對象的類型和擔心類型匹配問題了。同時大部分情況下也不用做類型強制轉換工作了。

ListContainer myContainer = new ListContainer();

myContainer.setObj("123");

myContainer.setObj(new Dog());//編譯器就提醒類型異常

ArrayList objectList = new ArrayList();

objectList.add(myContainer);

Integer myStr = (objectList.get(0)).getObj(); //編譯時提醒類型異常

String myStr = (objectList.get(0)).getObj();


  當然泛型的<>里也可以放多個參數,如:

public class MultiContainer {

private T t;

private S s;

...

MultiContainer multicon=new MultiContainer();


  

有界泛型


  看看這個泛型和多態的問題,Dog,Cat是Animal的子類:

public void killAll(ArrayList animals){...};//Animal容器

...

ArrayList animals=new ArrayList();

animals.add(new Dog());

animals.add(new Cat());

killAll(animals);//這裡ok

ArrayList dogs=new ArrayList();//Dog是Animal的子類

dogs.add(new Dog());

dogs.add(new Dog());

killAll(dogs);//這裡編譯不通過


  在這裡看上去似乎多態不行了。


  這裡就要用到有界泛型:


  在使用泛型時,我們會有這種需求:需要指定泛型的類型範圍。有界類型就是在類型參數部分指定extends或super關鍵字,這裡的extends也含有implements的功能,分別用上限或下限來限制類型範圍,從而限制泛型的類型邊界。例如:

//限定T是Animal的子類

//限定T是Dog的超類

  那麼上面那個多態問題就變成:

public void killAll(ArrayList animals){...};


  解決了。


  

多個限定時我們可以使用&來進行分割,這時關鍵詞只能使用extends。與多重繼承類似,這裡只有一個類其他都是介面。


  

泛型方法

  有時,我們設計的方法可能其參數類型是不限定的。這種場景如果用重載方法的方式來做的話,演算法重複,不是最好的方案。此時泛型方法就可以解決此類問題。


  如Calculator的add方法:

public static double add(N a, N b){

double sum = 0;

sum = a.doubleValue() + b.doubleValue();

return sum;

}


  如果用重載來做的話,要很多重複代碼了。


via:http://www.jianshu.com/p/5179ede4c4cf


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 全棧開發者中心 的精彩文章:

CSS常見布局解決方案
使用 LVS 實現負載均衡原理及安裝配置詳解
我必須得告訴大家的MySQL優化原理

TAG:全棧開發者中心 |

您可能感興趣

看完這篇,終於知道自己會不會 C# 泛型了
Swift 項目中涉及到 JSONDecoder,網路請求,泛型協議式編程的一些記錄和想法
scala學習-泛型、界定、形變、this.type、複合類型、抽象類型
Swift 泛型
技術分分享:Kotlin 泛型之類型擦除
Kotlin 泛型
Swift 運用協議泛型封裝網路層
Kotlin語言中的泛型設計哲學
Android 泛型與ArrayAdapter適配器 初步入門
封裝網路請求之-通過Gson轉換多級泛型