作者:帥地
公眾號:苦逼的碼農(ID:di201805)
下面我總結了集合、泛型、數組轉集合等一些常見的陷進,認真看完,相信你絕對有所收穫。
1、List ,List> 與 List<object> 有區別嗎?/<object>
說實話,我敢保證很多人是不知道 List, List> 與 List<object> 之間的區別的。/<object>
1、我們先來看看 List 與 List<object>
很多可能覺得 List<object>的用法與 List 是一樣的,例如很多人認為/<object>
List<object> list;/<object>
與
List list;
這兩種定義方法是一模一樣的,然而他們是不一樣的。看下面一段代碼
List<integer> t1 = new ArrayList<>();
// 編譯通過
List t2 = t1;
//編譯失敗
List<object> t3 = t1;
/<object>/<integer>
t1 可以賦給 t2, 但是 t1 不能賦給 t3,會拋出如下異常
從這裡可以看出
List list;
與
List<object> list;/<object>
是有區別的,List 變量可以接受任何泛型的變量,而 List 則不可以。
2、我們在看看 Lis> 有什麼需要注意的地方:
看下面一段代碼:
List> 是一個泛型,在沒有賦值之前,是可以接受任何集合的賦值的,我想這點大家都知道,但是請注意,賦值之後就不能往裡面添加元素了,提示如下錯誤:
所以 List> 一般用來作為參數來接受外部的集合,或者返回一個不知道具體元素的集合。
List 與 List>, List<object> 的細微區別知道了吧?/<object>
2、 extends T> 與 super T>你真的懂嗎?
我們知道泛型 List 只能放置一種類型,如果你採用 List<object> 來放置多種類型,然後再進行類型強制轉換的話,那會失去了泛型的初衷。/<object>
為了能夠放置多種類型,於是有了 extend T> 與 super T>,下面先說一些你可能原本就知道的知識:
1、對於 extends T> a,a 這個變量可以接受 T 及其 T 子類的集合,上界為 T,並且從 a 取出來的類型都會被強制轉換為 T。重點看下面一個例子:
注意:我們先約定 Cat(貓) 繼承自 Animal(動物),RedCat(黑貓) 繼承自 Cat注意, extends T>最需要注意的是,就是不能向裡面添加除null之外的其他所有元素,這個和 List> 有點類似。
2、現在說說 super T>,它和 extends T> 有點相反。對於 super T> a,a 這個變量可以接受 T 及其 T 父類的集合,下界為 T,並且從 a 取出來的類型都會被強制轉換為 Object。重點看下面一個例子:
注意,最需要注意的是,在雖然可以接受 T 及其父類的賦值,但是隻能向裡面添加 T 及其 T 的子類。
總結
1、List extends T> a ,可以把 a 及其 a 的子類賦給 a,從 a 裡取的元素都會被強制轉換為 T 類型,不過需要注意的是,不能向 a 添加任何除 null 外是元素。
2、List super T> a ,可以把 a 及其 a 的父類賦給 a,從 a 裡取的元素都會被強制轉換為 Object 類型,不過需要注意的是,可以向 a 添加元素,但添加的只能是 T 及其子類元素。
3、泛型與重載
我們先來看一道題,你覺得下面這道題能夠編譯通過嗎?
答是編譯不通過。
兩個方法的參數不同,為什麼會重載不通過呢?
實際上在 Java 的泛型中,泛型只存在於源碼中,在編譯後的字節碼中,泛型已經被替換為原生類型了,並且在相應的地方插入了強制轉換的代碼。為了方便理解,可以看下面的一段代碼例子:
編譯之後泛型就不存在了,並且在相應的地方插入了強制轉換的代碼,編譯之後,我們反編譯的代碼如下:
這種 編譯之後泛型就不存在了,並且在相應的地方插入了強制轉換代碼的機制我們也稱之為擦除。
所以上面的兩個方法,看似參數不一樣,但是經過編譯擦出之後,他們的參數就是一樣的了,所以編譯不通過。
4、數組與集合相互轉換時需要注意的點
1、數組轉集合
大家先看一個例子吧,
向集合添加元素拋出瞭如下異常:
問題來了,向集合添加元素為啥會拋出異常呢??
我們先來看一下 Arrays.asList(arr) 方法究竟返回了什麼?
源碼如下:
返回的明明是 ArrayList 啊,為啥就不能添加元素呢??
實際上,此 ArrayList 非彼 ArrayList,這個返回的 ArrayList 實際上是 Arrays 的一個
而且這個假的 ArrayList 是直接 引用原數組的,不然你看它的構造器(第二條畫線)
也就是說,ArrayList 內部是直接引用 arr 數組,你對 arr 數組進行改變,也會同時改變到 list 集合。
下面的代碼證明這一點
打印結果是 “0”。
所以,我們向 list 添加元素肯定失敗,因為 arr 數組的長度了 3 ,本來就有 3 個元素了,你在向裡面添加第四個元素,肯定是不行的。
所以,在把數組轉換為集合的過程中,需要特別注意。
建議大家這樣轉換比較安全
List<string> list = new ArrayList<>(Arrays.asList(arr));
/<string>
2、集合轉數組
集合轉換為數組相對比較不苛刻,我就不拉很多源碼來進行分析了,我只簡單說下幾個需要注意的地方。例如對於下面這個轉換:
// 集合大小為 size
List<string> list = new ArrayList<>();
// 長度為 n 的數組
String[] arr = new String[n];
// 進行轉換
list.toArray(arr);
/<string>
1、如果數組長度比集合小:由於 arr 的長度不夠,所以集合裡的元素不會賦給 arr,而且自己再重新創建一個新數組反回去。
2、如果數組長度不小於集合:此時 arr 的長度夠了,所以集合裡的元素直接複製給 arr 數組,不會重新創建一個新的元素。
一覽源碼:
以上這些陷進相信有不少人是不知道了,我把它總結整理了出來,如果大家看完覺得有收穫,不妨點個好看鼓勵我一下?