多次聽到泛型擦除也看過不少的博客解釋,但始終都是看的時候覺得挺有道理一轉眼就忘的一乾二淨,歸根結底是沒有自己的認識。所以我今天翻看了ArrayList的實現源碼來真真正的認識一下泛型擦除。
我們都用過ArraryList類,都知道他是一個容器類,並且從javase5之後是一個類型安全的容器類(我們再使用他的時候必須指定這個泛型的具體類型,然後在使用他的過程中也只能向這個容器中添加這個類型的對象,最後使用get方法獲得的也一定是這個類型的對象),具體使用如下所示:
package test;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Apple> list = new ArrayList<Apple>(); //"<>"中指定泛型的具體類型爲Apple
list.add(new Apple()); //添加Apple類型的對象,成功
//list.add(new Orrange()); //添加Orrange類型的對象,報錯
}
static class Apple {
}
static class Orrange {
}
}
按照這個思路思考的話,那ArrayList中保存的就應該是Apple類型的對象,而不是其他的類型,但事實上卻不是這樣。在ArrayList中Apple的對象卻是以Object類型進行保存(進行了向上轉型),並不是以我們指定的Apple類型進行保存。來看源碼:
可以看到elementData數組的類型爲Object類型,add方法直接將添加的對象添加到了elementData數組。這種對象保存到容器中失去了原來的類型統一轉型爲Object類型的現象就叫泛型擦除。
現在我們就有疑問了,既然統一擦除了原來的類型那又怎麼保證get方法得到的對象不是Object類型而是對象的原來類型呢?接下來我們看get方法的源碼:
可以看到在每次返回元素的時候都是用了"(E)"進行強轉。這樣我們get到的結果就是原來的類型了。
添加數據的時候上轉爲Object類型,查找數據的時候有強轉爲原來的類型,這樣轉過來轉過去的有什麼意義呢?爲什麼直接創建一個E類型的數組而多此一舉的創建Object類型的數組呢?原因是泛型是不能創建數組的
public class Apple<E> {
E []e = {}; //報錯
E []ee = new E[10]; //報錯
}