国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java泛型:類型擦除

Hanks10100 / 1239人閱讀

博客地址:Java泛型:類型擦除

前情回顧

Java泛型:泛型類、泛型接口和泛型方法

類型擦除 代碼片段一
Class c1 = new ArrayList().getClass();
Class c2 = new ArrayList().getClass(); 
System.out.println(c1 == c2);

/* Output
true
*/

顯然在平時使用中,ArrayList()new ArrayList()是完全不同的類型,但是在這里,程序卻的的確確會輸出true

這就是Java泛型的類型擦除造成的,因為不管是ArrayList()還是new ArrayList(),都在編譯器被編譯器擦除成了ArrayList。那編譯器為什么要做這件事?原因也和大多數的Java讓人不爽的點一樣——兼容性。由于泛型并不是從Java誕生就存在的一個特性,而是等到SE5才被加入的,所以為了兼容之前并未使用泛型的類庫和代碼,不得不讓編譯器擦除掉代碼中有關于泛型類型信息的部分,這樣最后生成出來的代碼其實是『泛型無關』的,我們使用別人的代碼或者類庫時也就不需要關心對方代碼是否已經『泛化』,反之亦然。

在編譯器層面做的這件事(擦除具體的類型信息),使得Java的泛型先天都存在一個讓人非常難受的缺點:

在泛型代碼內部,無法獲得任何有關泛型參數類型的信息。

代碼片段二
List list = new ArrayList();
Map map = new HashMap();
System.out.println(Arrays.toString(list.getClass().getTypeParameters()));
System.out.println(Arrays.toString(map.getClass().getTypeParameters()));

/* Output
[E]
[K, V]
*/

關于getTypeParameters()的解釋:

Returns an array of TypeVariable objects that represent the type variables declared by the generic declaration represented by this GenericDeclaration object, in declaration order. Returns an array of length 0 if the underlying generic declaration declares no type variables.

我們期待的是得到泛型參數的類型,但是實際上我們只得到了一堆占位符。

代碼片段三
public class Main {

    public T[] makeArray() {
        // error: Type parameter "T" cannot be instantiated directly
        return new T[5];
    }
}

我們無法在泛型內部創建一個T類型的數組,原因也和之前一樣,T僅僅是個占位符,并沒有真實的類型信息,實際上,除了new表達式之外,instanceof操作和轉型(會收到警告)在泛型內部都是無法使用的,而造成這個的原因就是之前講過的編譯器對類型信息進行了擦除。

同時,面對泛型內部形如T var;的代碼時,記得多念幾遍:它只是個Object,它只是個Object……

代碼片段四
public class Main {

    private T t;

    public void set(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public static void main(String[] args) {
        Main m = new Main();
        m.set("findingsea");
        String s = m.get();
        System.out.println(s);
    }
}

/* Output
findingsea
*/

雖然有類型擦除的存在,使得編譯器在泛型內部其實完全無法知道有關T的任何信息,但是編譯器可以保證重要的一點:內部一致性,也是我們放進去的是什么類型的對象,取出來還是相同類型的對象,這一點讓Java的泛型起碼還是有用武之地的。

代碼片段四展現就是編譯器確保了我們放在t上的類型的確是T(即便它并不知道有關T的任何類型信息)。這種確保其實做了兩步工作:

set()處的類型檢驗

get()處的類型轉換

這兩步工作也成為邊界動作

代碼片段五
public class Main {

    public List fillList(T t, int size) {
        List list = new ArrayList();
        for (int i = 0; i < size; i++) {
            list.add(t);
        }
        return list;
    }

    public static void main(String[] args) {
        Main m = new Main();
        List list = m.fillList("findingsea", 5);
        System.out.println(list.toString());
    }
}

/* Output
[findingsea, findingsea, findingsea, findingsea, findingsea]
*/

代碼片段五同樣展示的是泛型的內部一致性。

擦除的補償

如上看到的,但凡是涉及到確切類型信息的操作,在泛型內部都是無法共工作的。那是否有辦法繞過這個問題來編程,答案就是顯示地傳遞類型標簽。

代碼片段六
public class Main {

    public T create(Class type) {
        try {
            return type.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        Main m = new Main();
        String s = m.create(String.class);
    }
}

代碼片段六展示了一種用類型標簽生成新對象的方法,但是這個辦法很脆弱,因為這種辦法要求對應的類型必須有默認構造函數,遇到Integer類型的時候就失敗了,而且這個錯誤還不能在編譯器捕獲。

進階的方法可以用限制類型的顯示工廠和模板方法設計模式來改進這個問題,具體可以參見《Java編程思想 (第4版)》P382。

代碼片段七
public class Main {

    public T[] create(Class type) {
        return (T[]) Array.newInstance(type, 10);
    }

    public static void main(String[] args) {
        Main m = new Main();
        String[] strings = m.create(String.class);
    }
}

代碼片段七展示了對泛型數組的擦除補償,本質方法還是通過顯示地傳遞類型標簽,通過Array.newInstance(type, size)來生成數組,同時也是最為推薦的在泛型內部生成數組的方法。

以上,泛型的第二部分的結束。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64658.html

相關文章

  • Java 泛型總結(一):基本用法與類型擦除

    摘要:然而中的泛型使用了類型擦除,所以只是偽泛型。總結本文介紹了泛型的使用,以及類型擦除相關的問題。一般情況下泛型的使用比較簡單,但是某些情況下,尤其是自己編寫使用泛型的類或者方法時要注意類型擦除的問題。 簡介 Java 在 1.5 引入了泛型機制,泛型本質是參數化類型,也就是說變量的類型是一個參數,在使用時再指定為具體類型。泛型可以用于類、接口、方法,通過使用泛型可以使代碼更簡單、安全。然...

    Java_oldboy 評論0 收藏0
  • Java系列之泛型

    摘要:總結泛型的類型必須是引用類型,不能是基本類型,泛型的個數可以有多個,可以使用對創建對象時的泛型類型以及方法參數類型進行限制,如使用關鍵字和對泛型的具體類型進行向下限制或向上限制,最后一點,可以聲明泛型數組,但是不能創建泛型數組的實例。 自從 JDK 1.5 提供了泛型概念,泛型使得開發者可以定義較為安全的類型,不至于強制類型轉化時出現類型轉化異常,在沒有反省之前,可以通過 Object...

    MadPecker 評論0 收藏0
  • 初探Java類型擦除

    摘要:可以看到,如果我們給泛型類制定了上限,泛型擦除之后就會被替換成類型的上限。相應的,泛型類中定義的方法的類型也是如此。參考語言類型擦除下界通配符和的區別 本篇博客主要介紹了Java類型擦除的定義,詳細的介紹了類型擦除在Java中所出現的場景。 1. 什么是類型擦除 為了讓你們快速的對類型擦除有一個印象,首先舉一個很簡單也很經典的例子。 // 指定泛型為String List list1 ...

    DevTalking 評論0 收藏0
  • 聊聊Java泛型及實現

    摘要:靜態變量是被泛型類的所有實例所共享的。所以引用能完成泛型類型的檢查。對于這個類型系統,有如下的一些規則相同類型參數的泛型類的關系取決于泛型類自身的繼承體系結構。事實上,泛型類擴展都不合法。 前言 和C++以模板來實現靜多態不同,Java基于運行時支持選擇了泛型,兩者的實現原理大相庭徑。C++可以支持基本類型作為模板參數,Java卻只能接受類作為泛型參數;Java可以在泛型類的方法中取得...

    lewif 評論0 收藏0
  • Java泛型總結

    摘要:靜態變量是被泛型類的所有實例所共享的。對于這個類型系統,有如下的一些規則相同類型參數的泛型類的關系取決于泛型類自身的繼承體系結構。在代碼中避免泛型類和原始類型的混用。參考泛型類型擦除 Java泛型總結 Java泛型是JDK5引入的一個新特性,允許在定義類和接口的時候使用類型參數(type parameter)。聲明的類型參數在使用的時候使用具體的類型來替換。泛型最主要的應用是在JDK5...

    CoreDump 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<