泛型的意義和作用是啥?
簡單的說,意義和作用有:
類型的參數化,就是可以把類型像方法的參數那樣傳遞。這一點意義非凡。
泛型使編譯器可以在編譯期間對類型進行檢查以提高類型安全,減少運行時由於對象類型不匹配引發的異常。
泛型方法,演算法的復用。蠻神奇的。
想要理解為什麼引入泛型,就要知道沒有泛型的麻煩。
我們知道現在的程序開發都是面向對象了,所以程序里會有很多各種類型的對象,對象多了肯定需要有某種類型的容器來裝。所以就有了一些容器類型,比如數組、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;
}
}
這裡
ListContainer
這種環境下,編譯器就知道ListContainer容器是放Dog類型對象的。並進行類型安全檢查。
myCon.setObj(new Dog())//ok
myCon.setObj(「123」);//編譯時提醒類型錯誤
這樣設計的容器在使用時編譯器就可以幫忙做很大一部分的類型安全檢查工作了,這就避免了很多運行時的ClassCastException異常,程序員也無需記住各種對象的類型和擔心類型匹配問題了。同時大部分情況下也不用做類型強制轉換工作了。
ListContainer
myContainer.setObj("123");
myContainer.setObj(new Dog());//編譯器就提醒類型異常
ArrayList objectList
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
有界泛型
看看這個泛型和多態的問題,Dog,Cat是Animal的子類:
public void killAll(ArrayList
...
ArrayList
animals.add(new Dog());
animals.add(new Cat());
killAll(animals);//這裡ok
ArrayList
dogs.add(new Dog());
dogs.add(new Dog());
killAll(dogs);//這裡編譯不通過
在這裡看上去似乎多態不行了。
這裡就要用到有界泛型:
在使用泛型時,我們會有這種需求:需要指定泛型的類型範圍。有界類型就是在類型參數部分指定extends或super關鍵字,這裡的extends也含有implements的功能,分別用上限或下限來限制類型範圍,從而限制泛型的類型邊界。例如:
那麼上面那個多態問題就變成:
public void killAll(ArrayList
解決了。
多個限定時我們可以使用&來進行分割,這時關鍵詞只能使用extends。與多重繼承類似,這裡只有一個類其他都是介面。
泛型方法
有時,我們設計的方法可能其參數類型是不限定的。這種場景如果用重載方法的方式來做的話,演算法重複,不是最好的方案。此時泛型方法就可以解決此類問題。
如Calculator的add方法:
public static
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轉換多級泛型