標籤:world nts 引入 tor 定義 collect 是什麼 for sys
1. 泛型出現前後代碼對比
先來看看泛型出現前,代碼是這麼寫的:
List words = new ArrayList();words.add("Hello ");words.add("worlds!");String s = (String) words.get(0) + (String) words.get(1);System.out.println(s.equals("Hello worlds!"));
而泛型出現後無需做顯式轉換:
words.add("Hello ");words.add("worlds!");String s = words.get(0) + words.get(1);System.out.println(s.equals("Hello worlds!"));
從本質上來說,以上代碼編譯為位元組碼後是一樣的,對JVM而言沒有區別。
2. 為什麼有泛型?
泛型是什嗎?
泛型允許程式員編寫代碼時使用一些以後才指定的類型,允許在定義類和介面的時候使用型別參數,java泛型的參數只可以代表類,不能代表個別對象。
泛型的引入可以解決之前的集合類架構在使用過程中通常會出現的運行時刻類型錯誤[1]。
interface Iterator<E> { public boolean hasNext(); public E next(); public void remove(); ...}
泛型方法也可以哦:
class List { public static<T> List<T> toList(T[] arr) { List<T> list = new ArrayList<T>(); for (T elt : arr) list.add(elt); return list; }}
為什麼有泛型?
1) 泛型可以隱式地執行類型轉換,並且永遠不會失敗(cast-iron guarantee[2]):
1 List<String> words = new ArrayList<String>();2 由於泛型的類型擦除特性,所有添加到words中的變數,都會被轉換為Object,3 此時就需要泛型的類型轉換特性,在執行words.get(i)時做強制轉換。
2) 泛型由於類型擦除特性(後面的章節介紹),如List<Integer>,List<String>,List<Number>編譯成位元組碼是一樣的,
而不是每一個都有一個版本,保持著簡潔性。
3) 最後也是最後要的一點:泛型的相容性,可相容jdk1.4以前的版本。從JVM的角度看,由於泛型代碼編譯成位元組碼與jdk1.4
之前的代碼無任何差別,因此可以很容易的修改jdk1.4寫的函數庫中的某一個函數,而無需修改整個函數庫。
3. 泛型萬用字元
首先以一個樣本講解為什麼需要泛型萬用字元,如果我們定義addAll方法如下所示:
interface Collection<E> {... public boolean addAll(Collection<E> c);...}/** **測試代碼**/List<Number> nums = new ArrayList<Number>();List<Integer> ints = Arrays.asList(1,2,3);nums.addAll(ints); // 編譯錯誤
如果我們想在List<Number>中添加List<Integer>怎麼辦呢?這是就需要使用萬用字元了。
interface Collection<E> {... public boolean addAll(Collection<? extends E> c);...}/** **測試代碼**/List<Number> nums = new ArrayList<Number>();List<Integer> ints = Arrays.asList(1,2,3);List<Double> dbls = Arrays.aslist(3.14,3.21);nums.addAll(ints); nums.addAll(dbls);
從上述代碼可以看出,萬用字元的出現解決了泛型的子類問題:
List<Integer>與List<Double>都是List<? extends Number>的子類;而不是 List<Number>的子類。
最後,給出一個結論:當S是T的子類時,List<S>是List<?extends T>的子類;
當S是T的超類時,List<S>是List<? super T>的子類。此外,List<?>是List<? extends Object>的縮寫。
接下來,我們分析萬用字元的重要的特性——put and get原則[2]。
對extends而言,List<? extends T>只能get不能add或put。
List<Integer> ints = new ArrayList<Integer>();ints.add(1);ints.add(2);List<? extends Number> nums = ints;
System.out.println(nums.get(0)); // 編譯成功nums.add(3); // 編譯錯誤nums.add(3.14); // 編譯錯誤
對於super而言,List<? super T>只能put或add,不能get。
List<Number> ints = new ArrayList<Number>();ints.add(1);ints.add(2);List<? super Integer> nums = ints;nums.add(3);
凡是都有例外,對於extends來說,List<? extends Number> nums可以add null,即nums.add(null);對於super來說,
List<? super Integer> nums 可以get(取出)Object對象。
4. 參考文獻
[1] http://www.infoq.com/cn/articles/cf-java-generics
[2] java Generics and Collections
java泛型探索——介紹篇