java中的類型擦除type erasure


java中的類型擦除type erasure

簡介

泛型是java從JDK 5開始引入的新特性,泛型的引入可以讓我們在代碼編譯的時候就強制檢查傳入的類型,從而提升了程序的健壯度。

泛型可以用在類和接口上,在集合類中非常常見。本文將會講解泛型導致的類型擦除。

舉個例子

我們先舉一個最簡單的例子:

@Slf4j
public class TypeErase {

    public static void main(String[] args) {
        ArrayList<String> stringArrayList = new ArrayList<String>();
        stringArrayList.add("a");
        stringArrayList.add("b");
        action(stringArrayList);
    }

    public static void action(ArrayList<Object> al){
        for(Object o: al)
            log.info("{}",o);
    }
}

上面的例子中,我們定義了一個ArrayList,其中指定的類型是String。

然後調用了action方法,action方法需要傳入一個ArrayList,但是這個list的類型是Object。

乍看之下好像沒有問題,因爲String是Object的子類,是可以進行轉換的。

但是實際上代碼編譯出錯:

Error:(18, 16) java: 不兼容的類型: java.util.ArrayList<java.lang.String>無法轉換爲java.util.ArrayList<java.lang.Object>

原因

上面例子的原因就是類型擦除(type erasure)。java中的泛型是在編譯時做檢測的。而編譯後生成的二進制文件中並不保存類型相關的信息。

上面的例子中,編譯之後不管是ArrayList<String> 還是ArrayList<Object> 都會變成ArrayList。其中的類型Object/String對JVM是不可見的。

但是在編譯的過程中,編譯器發現了兩者的類型不同,然後拋出了錯誤。

解決辦法

要解決上面的問題,我們可以使用下面的辦法:

    public static void actionTwo(ArrayList<?> al){
        for(Object o: al)
            log.info("{}",o);
    }

通過使用通配符?,可以匹配任何類型,從而通過編譯。

但是要注意這裏actionTwo方法中,因爲我們不知道傳入的類型到底是什麼,所以我們不能在actionTwo中添加任何元素。

總結

從上面的例子我們可以看出,ArrayList<String>並不是ArrayList<Object>的子類。如果一定要找出父子關係,那麼ArrayList<String>是Collection<String>的子類。

但是Object[] objArray是String[] strArr的父類。因爲對Array來說,其具體的類型是已知的。

本文的例子https://github.com/ddean2009/learn-java-collections

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/java-type-erasure/

本文來源:flydean的博客

歡迎關注我的公衆號:程序那些事,更多精彩等着您!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章