Arrays工具類有一個方法asList可以把一個變長參數或數組轉變為列表,但是它有一個缺點:它所生成的List長度是不可改變的,而這在我們的項目開發中有時會很不方便。如果你期望生成的列表長度是可變,那就需要自己來寫一個數組的工具類了,代碼如下:
class ArrayUtils{
//把一個變長參數轉變為列表,並且長度可變
public static<T>List<T>asList(T……t){
List<T>list=new ArrayList<T>();
Collections.addAll(list, t);
return list;
}
}
這很簡單,與Arrays.asList的調用方式相同,我們傳入一個泛型對象,然後返回相應的List,代碼如下:
public static void main(Stringargs){
//正常用法
List<String>list1=ArrayUtils.asList("A","B");
//參數為空
List list2=ArrayUtils.asList();
//參數為數字和字符串的混合
List list3=ArrayUtils.asList(1,2,3.1);
}
這裡有三個變量需要說明:
(1)變量list1
變量list1是一個常規用法,沒有任何問題,泛型實際的參數類型是String,返回的結果也就是一個容納String元素的List對象。
(2)變量list2
變量list2中容納的是什麼元素呢?我們無法從代碼中推斷出list2列表到底容納的是什麼元素(因為它傳遞的參數是空,編譯器也不知道泛型的實際參數類型是什麼),不過,編譯器會很「聰明」地推斷出最頂層類Object就是其泛型類型,也就是說list2的完整定義如下:
List<Object>list2=ArrayUtils.asList();
如此一來,編譯時就不會給出"unchecked"警告了。現在新的問題出現了:如果期望list2是一個Integer類型的列表,而不是Object列表,因為後續的邏輯會把Integer類型加入到list2中,那該如何處理呢?
強制類型轉化(把asList強制轉換成List<Integer>)?行不通,雖然Java的泛型是編譯擦除式的,但是List<Object>和List<Integer>沒有繼承關係,不能進行強制轉換。
重新聲明一個List<Integer>,然後讀取List<Object>元素,一個一個地向下轉型過去?麻煩,而且效率又低。
最好的解決方法是強制聲明泛型類型,代碼如下:
List<Integer>list2=ArrayUtils.<Integer>asList();
就這麼簡單,asList方法要求的是一個泛型參數,那我們就在輸入前定義這是一個Integer類型的參數,當然,輸出也是Integer類型的集合了。
(3)變量list3
變量list3有兩種類型的元素:整數類型和浮點類型,那它生成的List泛型化參數應該是什麼呢?是Integer和Float的父類Number?你太高看編譯器了,它不會如此推斷的,當它發現多個元素的實際類型不一致時就會直接確認泛型類型是Object,而不會去追索元素類的公共父類是什麼,但是對於list3,我們更期望它的泛型參數是Number,都是數字嘛!參照list2變量,代碼修改如下:
List<Number>list3=ArrayUtils.<Number>asList(1,2,3.1);
Number是Integer和Float的父類,先把三個輸入參數向上轉型為Number,那麼返回的結果也就是List<Number>類型了。
通過強制泛型參數類型,我們明確了泛型方法的輸入、輸出參數類型,問題是我們要在什麼時候明確泛型類型呢?一句話:無法從代碼中推斷出泛型類型的情況下,即可強制聲明泛型類型。