本篇博文主要介紹兩部分,爲何要有泛型以及泛型擦除這個概念,若是你想要了解泛型的具體使用,請查看相關書籍或者其餘博客。java
來看看官方文檔給的解釋:安全
Code that uses generics has many benefits over non-generic code:app
Stronger type checks at compile time. A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.ui
Elimination of casts.this
The following code snippet without generics requires casting:code
List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0);When re-written to use generics, the code does not require casting:blog
List<String> list = new ArrayList<String>(); list.add("hello"); String s = list.get(0); // no castEnabling programmers to implement generic algorithms. By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.ip
文檔中主要列舉了三個使用泛型的理由。文檔
首先,若是代碼中有使用泛型的話,編譯器就會進行類型檢查,當代碼中違反了類型安全的規範,那麼編譯就不會經過。在編譯期間修改錯誤相對來講比在運行期間修改錯誤容易得多。get
其次,泛型能夠消除類型轉換的錯誤。最多見的一個例子是在集合類的使用中,在沒有使用泛型以前,集合類中能夠添加任何的類型,當咱們須要獲取容器中的元素時,就要進行類型轉換:
List list = new ArrayList(); list.add("hello"); String s = (String)list.get(0);
通常狀況下,這種作法是沒問題的。可是,當咱們添加的元素既有 String 又有其餘類型時,上面的代碼在運行期間就很容易報錯。使用泛型以後,咱們就只能向容器中添加單一的元素,這樣就能夠很好地解決該問題,除此以外,獲取元素時也能夠不用進行類型的轉換了,十分方便。
最後,咱們能夠使用泛型方法來提升方法的重用性。當咱們有兩個方法,一個方法返回 String,另外一個方法返回 int,若是不使用泛型的話,咱們須要寫兩個方法:
public String getString(String message){ return message; } public int getInt(int message){ return message; }
咱們能夠看到,上面兩個方法體實際上是同樣的,分紅兩個方法寫不免有點冗餘,這時泛型方法就能夠派上用場了。使用泛型方法,不只使代碼的冗餘度下降了,對於返回類型咱們也不用進行類型轉換,一箭雙鵰,何樂而不爲呢?
public <T> T getMessage(T message) { return message; }
瞭解了爲何要使用泛型後,咱們來看看泛型中另外一個重要的概念 --- 泛型擦除。首先咱們來看一下這個例子:
public class ErasedTRypeEquivalence { public static void main(String[] args) { Class c1 = new ArrayList<String>().getClass(); Class c2 = new ArrayList<Integer>().getClass(); System.out.println(c1 == c2); } }
Class 類包含的是類信息,直觀的來看,ArrayList<String> 和 ArrayList<Integer> 二者包含的類信息應該是不同的,可是運行的結果倒是 true。這是由於泛型只在編譯期間才起做用,在運行期間,泛型信息都會被擦除成「原生」類型,上面的 ArrayList<String> 和 ArrayList<Integer> 會被擦除爲 ArrayList<Object>。舉個例子,當咱們使用泛型時,在調用 ArrayList.add() 方法時,編譯器會提醒咱們須要添加的元素爲 Integer 類型
可是在運行期間,其 add 方法能夠添加的元素仍然是 Object 類型。怎麼驗證這一點呢?看下面這段代碼:
public class EraseTest { public static void main(String[] args) { Apple<Integer> a = new Apple<>(6); Field[] fs = a.getClass().getDeclaredFields(); for(Field f : fs) { System.out.println(f.getType().getName()); } } } class Apple<T>{ T size; public Apple(T size) { this.size = size; } }
咱們爲 Apple 指定的泛型是 Integer,按照常理,size 的類型也應該是 Integer,可是上面的代碼卻打印出 java.lang.Object
,因而可知,泛型只是存在於編譯期間,在運行期間其類型會被擦除。有了泛型擦除這個概念,咱們就能夠更好的理解使用泛型過程當中編譯器的警告以及錯誤提示,對於泛型的一些特性也可以更好的理解。
這篇文章就到這邊了,若是其中有什麼問題的話歡迎評論留言!