国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Java】 泛型擦除

這篇具有很好參考價(jià)值的文章主要介紹了【Java】 泛型擦除。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1. 泛型擦除的介紹

1.1 泛型擦除的原因

  1. 原因一:JDK1.5及1.5之前都是沒有泛型的概念的,JDK1.5之后引入了泛型的概念并為了與之前的JDK版本兼容,所以引入了泛型擦除的概念。
  2. 原因二:若對(duì)每個(gè)泛型類型都生成不同的目標(biāo)代碼,現(xiàn)有10個(gè)不同泛型的List,就要生成10份字節(jié)碼,這樣會(huì)造成不僅造成代碼膨脹,而且一份字節(jié)碼對(duì)應(yīng)一個(gè)Class對(duì)象,占據(jù)大量的內(nèi)存。

1.2 泛型擦除規(guī)則

  1. 情況一:首先將 所有聲明泛型的地方 都擦除,然后若 定義該泛型的地方 沒有指定泛型上界,則 所有該泛型類型的變量的數(shù)據(jù)類型 在編譯之后都替換為Object
    java 泛型擦除,# JavaSE,java,泛型擦除

  2. 情況二:首先將 所有聲明泛型的地方 都擦除,然后若 定義該泛型的地方 指定了泛型上界,則 所有該泛型類型的變量的數(shù)據(jù)類型 在編譯之后都替換為泛型上界
    java 泛型擦除,# JavaSE,java,泛型擦除

  • 例題1:
    java 泛型擦除,# JavaSE,java,泛型擦除
  • 例題2:
    java 泛型擦除,# JavaSE,java,泛型擦除

1.3 泛型擦除規(guī)則的驗(yàn)證

  1. 方式一:通過Class對(duì)象驗(yàn)證:想通過Class對(duì)象獲取泛型信息,但是僅僅獲取的泛型信息是占位符,并不是實(shí)際的泛型類型
    List<Integer> list = new ArrayList<Integer>();  
    Map<Integer, String> map = new HashMap<Integer, String>();  
    System.out.println(Arrays.toString(list.getClass().getTypeParameters())); // 輸出:[E] 
    System.out.println(Arrays.toString(map.getClass().getTypeParameters()));  // 輸出:[K, V]
    
  2. 方式二:通過反射機(jī)制驗(yàn)證:我們知道泛型只是用來對(duì)變量類型進(jìn)行約束,這個(gè)約束只在編譯階段有效,在編譯之后泛型就被擦除了。比如:
    java 泛型擦除,# JavaSE,java,泛型擦除
    因此,如果可以繞過編譯階段對(duì)泛型的約束檢測(cè),那么就可以傳入任何類型的變量(因?yàn)槎伎梢韵蛏限D(zhuǎn)型為Object類型):
    ArrayList<String> list = new ArrayList<>();
    list.add("張三");
    list.add("李四");
    
    // 通過反射繞過編譯
    Class clazz = list.getClass();
    Method method = clazz.getMethod("add", Object.class); // 這里必須是Object,因?yàn)榉盒筒脸?guī)則:ArrayList<E>中E沒有泛型上界,所以泛型擦除后占位符E用Object代替
    method.invoke(list, 21);
    
    // 打印該集合
    System.out.println(list);
    System.out.println(list.get(2));
    
    運(yùn)行結(jié)果為:
    java 泛型擦除,# JavaSE,java,泛型擦除

2. 使用反射獲取被擦除泛型信息的技巧

  • 問:進(jìn)行泛型擦除后的程序就能夠在JDK1.5上正確執(zhí)行了,那么還有必要保存原本的泛型信息嗎?

  • 答:會(huì)保存。所有類會(huì)先將自己類中涉及的所有實(shí)際泛型備份放在自己類中,然后自己類再將進(jìn)行泛型擦除 【超級(jí)重要!?。。。。。。。。。。。。。。。。。。。。。。。 ?/strong>。

  • 原理及獲取方式:使用了泛型的類編譯為class文件時(shí)會(huì)生成一個(gè)signature字段,而原本的泛型信息就被保存在class文件中signature指向的常量池中。
    java 泛型擦除,# JavaSE,java,泛型擦除
    但是signature是一個(gè)private修飾的屬性,不能直接訪問,只能通過反射訪問。因?yàn)閏lass文件中會(huì)生成一些public修飾的方法能將訪問signature屬性并獲取相關(guān)信息。所以,在實(shí)際中一般采用這些方法來獲取泛型,而不是直接使用signature字段。具體方法為:
    java 泛型擦除,# JavaSE,java,泛型擦除

  • 例子:

    class A<T, ID> {  
    }  
      
    class B extends A<String, Integer> {  
    }  
      
    public class Generic {  
        public static void main(String[] args) {  
            ParameterizedType parameterizedType = (ParameterizedType) B.class.getGenericSuperclass();  
            
    		Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();  
    		for(Type actualTypeArgument: actualTypeArguments) {  
    		    System.out.println(actualTypeArgument);  
    		}  
        }  
    }  
    
    // 輸出:
    class java.lang.String
    class java.lang.Integer
    

3. 泛型擦除導(dǎo)致的兩大經(jīng)典問題的解決方案

泛型有3類:泛型類、泛型接口、泛型方法。但無論是哪種都會(huì)造成泛型擦除,而這也造成了問題:

  1. 問題1:由于泛型擦除,導(dǎo)致無法在 泛型類 中獲取實(shí)際泛型類型
    解決方法:使用匿名內(nèi)部類
  2. 問題2:由于泛型擦除,導(dǎo)致無法在 泛型接口 進(jìn)行 接口回調(diào) 之后獲取實(shí)際泛型類型
    解決方法:使用匿名內(nèi)部類
  3. 泛型方法的泛型擦除導(dǎo)致的問題,目前還沒有遇到,遇到了再補(bǔ)充?。?!

3.1 在泛型類中獲取實(shí)際泛型類型

根據(jù)泛型擦除規(guī)則知道類在編譯之后所有泛型都會(huì)被Object或者泛型上界代替,因此導(dǎo)致 泛型類 中無法獲取原本的泛型信息。

那么問題來了,我就是要獲取原本的泛型信息該怎么辦????

  • 比如:要實(shí)現(xiàn)以下需求
    java 泛型擦除,# JavaSE,java,泛型擦除
  • 有兩種方式實(shí)現(xiàn)該需求,這兩種方式都是借助反射實(shí)現(xiàn)該需求的:
    1. 方式一:將MyTest的class對(duì)象當(dāng)做參數(shù)傳入即可。但是這樣需要修改Stream類的代碼,也就是說要修改源碼
      ① 分析
      java 泛型擦除,# JavaSE,java,泛型擦除
      ② 解決方法:
      java 泛型擦除,# JavaSE,java,泛型擦除
    2. 方式二:使用匿名內(nèi)部類。這樣不用修改Stream類的代碼,也就是說不需要修改源碼,只要在使用該類的地方做修改即可
      1. 分析:找一個(gè)類來繼承泛型類,那么這個(gè)類就能保留泛型類的實(shí)際泛型類型:
        java 泛型擦除,# JavaSE,java,泛型擦除

        此時(shí),以上代碼從邏輯上就等價(jià)于以下代碼:
        java 泛型擦除,# JavaSE,java,泛型擦除
        如果還不能理解,請(qǐng)運(yùn)行以下代碼并思考:

        class A<T, ID> {  
        }  
          
        class B extends A<String, Integer> {  
        }  
          
        public class Generic {  
            public static void main(String[] args) {  
                ParameterizedType parameterizedType = (ParameterizedType) B.class.getGenericSuperclass();  
                
        		Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();  
        		for(Type actualTypeArgument: actualTypeArguments) {  
        		    System.out.println(actualTypeArgument);  
        		}  
            }  
        }  
        
        // 輸出:
        class java.lang.String
        class java.lang.Integer
        
      2. 最終解決方法:

        class Stream<E> {
            public Stream(List<E> list) {
                ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
                for (Type actualTypeArgument : genericSuperclass.getActualTypeArguments()) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
        
        public class MyTest {
            public static void main(String[] args) throws Exception {
                ArrayList<String> list = new ArrayList<>();
                Stream<String> stream = new Stream<String>(list) {
                };
            }
        }
        

3.2 在泛型接口進(jìn)行接口回調(diào)后獲取實(shí)際泛型類型

問題:對(duì)于函數(shù)式接口,如果使用匿名內(nèi)部類創(chuàng)建該接口對(duì)象的話,一般都會(huì)使用lambda表達(dá)式來代替匿名內(nèi)部類。但是,在某些情況下匿名內(nèi)部類不會(huì)報(bào)錯(cuò),而使用lambda表達(dá)式會(huì)報(bào)錯(cuò)。

  • 比如:要實(shí)現(xiàn)以下需求
    java 泛型擦除,# JavaSE,java,泛型擦除
    • 最重要的一個(gè)點(diǎn)就是Lambda表達(dá)式是將對(duì)應(yīng)的接口改造為對(duì)應(yīng)的類,并沒有構(gòu)造新的類來實(shí)現(xiàn)泛型接口。所以泛型接口的實(shí)際泛型類型無法保存。也就是說等價(jià)于以下代碼:
      java 泛型擦除,# JavaSE,java,泛型擦除
  • 有兩種方式實(shí)現(xiàn)該需求,這兩種方式都是借助反射實(shí)現(xiàn)該需求的:
    1. 方式一:將MyTest的class對(duì)象當(dāng)做參數(shù)傳入即可。但是這樣需要修改FlatMapFunc類的代碼,也就是說要修改源碼
      java 泛型擦除,# JavaSE,java,泛型擦除

    2. 方式二:使用匿名內(nèi)部類。這樣不用修改Stream類的代碼,也就是說不需要修改源碼,只要在使用該類的地方做修改即可

      java 泛型擦除,# JavaSE,java,泛型擦除文章來源地址http://www.zghlxwxcb.cn/news/detail-817181.html

到了這里,關(guān)于【Java】 泛型擦除的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 詳解Java中的泛型(泛型的語法,擦除機(jī)制,泛型的上界)

    詳解Java中的泛型(泛型的語法,擦除機(jī)制,泛型的上界)

    目錄 一.什么是泛型 二.Java中為什么要使用泛型 三.泛型的語法 四.泛型類的使用 五.泛型的編譯機(jī)制(擦除機(jī)制) 六.泛型的上界 泛型(Generics)是Java SE 5中引入的一個(gè)新特性,可以 使Java中的類和方法具有更廣泛的類型范圍 。通俗的說,它使得我們可以在定義類和方法時(shí)指定

    2024年02月05日
    瀏覽(24)
  • 【JavaSE】初識(shí)java

    【JavaSE】初識(shí)java

    目錄 Java語言概述 Java是什么 Java語言重要性 語言廣泛使用程度 工作領(lǐng)域 在校招中的崗位需求?編輯 Java語言發(fā)展簡史 Java語言特性 ?編輯Java開發(fā)環(huán)境安裝 初識(shí)Java的main方法 main方法示例 運(yùn)行Java程序 JDK、JRE、JVM之間的關(guān)系 注釋 基本規(guī)則 注釋規(guī)范 標(biāo)識(shí)符 ?編輯 總結(jié)

    2024年02月16日
    瀏覽(21)
  • JavaSE——初始java

    JavaSE——初始java

    目錄 一.Java是什么 二.Java語言的特性 1. 簡單性 2. 面相對(duì)象 3. 分布式(微服務(wù)) 4. 健壯性 5. 安全性 6. 體系結(jié)構(gòu)中立 7. 可移植性 8. 解釋性 9. 高性能 10. 多線程 11. 動(dòng)態(tài)性 三.JDK環(huán)境配置 1.簡介 2.安裝 ?3.配置 4.檢驗(yàn) 四.第一個(gè)Java程序 1.初始程序 2.運(yùn)行程序 3.JDK、JRE、JVM三者之間的

    2023年04月08日
    瀏覽(23)
  • 【JavaSE】Java的反射機(jī)制

    1.java反射機(jī)制 1.1簡介 被視為動(dòng)態(tài)語言的關(guān)鍵,允許程序在執(zhí)行期間,借助于RefectionAPI取得任何類的內(nèi)部信息。在程序的運(yùn)行狀態(tài)中,可以構(gòu)造任意一個(gè)類的對(duì)象,可以了解任意一個(gè)類對(duì)象所屬的類,可以了解任意一個(gè)類的成員變量和方法,可以調(diào)用任意一個(gè)對(duì)象的屬性和方

    2024年04月26日
    瀏覽(19)
  • 【JavaSE】第一個(gè)Java程序

    【JavaSE】第一個(gè)Java程序

    在JavaSE的系列中,將從第一個(gè)Java程序開始敘述,系統(tǒng)的把JavaSE的內(nèi)容總結(jié)一次。畢竟這是第二次學(xué)習(xí)JavaSE的內(nèi)容,因此感觸也相對(duì)比較深一些。在JavaSE的初步計(jì)劃中,大概有十一到十三篇文章,大致有:第一個(gè)Java程序、變量與運(yùn)算符、流程控制、面向?qū)ο螅ǚ庋b、繼承、多

    2024年01月22日
    瀏覽(14)
  • 【JavaSE】Java方法的使用

    【JavaSE】Java方法的使用

    【本節(jié)目標(biāo)】 1. 掌握方法的定義以及使用 2. 掌握方法傳參 3. 掌握方法重載 4. 掌握遞歸 目錄 1.方法概念及使用 1.1什么是方法(method) 1.2 方法定義 1.3 方法調(diào)用的執(zhí)行過程 1.4 實(shí)參和形參的關(guān)系 2. 方法重載 2.1 為什么需要方法重載 2.2 方法重載概念 3. 遞歸 3.1 生活中的故事 3.2 遞

    2024年02月12日
    瀏覽(23)
  • Java面試整理(二)《JavaSE》

    說明:我會(huì)根據(jù)我自己的經(jīng)驗(yàn),給每個(gè)內(nèi)容標(biāo)注重要程度,共有三個(gè)等級(jí):低、中、高。僅個(gè)人參考意見。 JVM是Java?Virtual?Machine的縮寫,是用于運(yùn)行Java字節(jié)碼的虛擬機(jī),JVM是運(yùn)行在操作系統(tǒng)之上,這也是Java程序?yàn)槭裁茨軌蜻\(yùn)行在不同的平臺(tái)或操作系統(tǒng)的原因。 JVM是Java語言

    2024年02月09日
    瀏覽(14)
  • 【JavaSE】java刷題--數(shù)組練習(xí)

    【JavaSE】java刷題--數(shù)組練習(xí)

    本篇講解了一些數(shù)組相關(guān)題目(主要以代碼的形式呈現(xiàn)),主要目的在于鞏固數(shù)組相關(guān)知識(shí)。 上一篇?數(shù)組?講解了一維數(shù)組和二維數(shù)組的基礎(chǔ)知識(shí)~ 歡迎關(guān)注個(gè)人主頁:逸狼 創(chuàng)造不易,可以點(diǎn)點(diǎn)贊嗎~ 如有錯(cuò)誤,歡迎指出~ 思路 首先要判斷 空指針和空數(shù)組 的情況,利用 字符

    2024年04月10日
    瀏覽(23)
  • 【JavaSE】Java基礎(chǔ)語法(十三):Java 中的集合(十分全面)

    【JavaSE】Java基礎(chǔ)語法(十三):Java 中的集合(十分全面)

    List (對(duì)付順序的好幫?): 存儲(chǔ)的元素是有序的、可重復(fù)的。 Set (注重獨(dú)???的性質(zhì)): 存儲(chǔ)的元素是?序的、不可重復(fù)的。 Queue (實(shí)現(xiàn)排隊(duì)功能的叫號(hào)機(jī)): 按特定的排隊(duì)規(guī)則來確定先后順序,存儲(chǔ)的元素是有序的、可重復(fù)的。 Map (? key 來搜索的專家): 使?鍵值對(duì)(key-value)存

    2024年02月10日
    瀏覽(26)
  • 【JavaSE】Java入門九(異常詳解)

    【JavaSE】Java入門九(異常詳解)

    目錄 異常? 1.Java中異常的體系結(jié)構(gòu) 2.異常的處理 3.自定義異常類 ? ? ?? 在Java中,將程序執(zhí)行過程中發(fā)生的不正常行為稱為異常,C語言中沒有這個(gè)概念,接下來我們重點(diǎn)需要掌握異常處理體系(try, catch, throw, finally)以及如何自定義異常類。 異常的種類繁多,Java內(nèi)部維護(hù)了

    2024年02月03日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包