<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java 泛型是什么?

          共 2225字,需瀏覽 5分鐘

           ·

          2021-12-19 08:14


          點擊上方?藍字?關(guān)注我們!



          2021 最新 Java 編程資料免費領(lǐng)!Java 視頻教程,Java Web 項目教程,互聯(lián)網(wǎng)Java 面試真題 / 算法題,簡歷模板,Linux 服務(wù)器等等,點擊領(lǐng)取


          來源:https://juejin.cn/post

          /6844903917835419661

          | 前言

          Java 泛型(generics)是 JDK 5 中引入的一個新特性, 泛型提供了編譯時類型安全檢測機制,該機制允許開發(fā)者在編譯時檢測到非法的類型。

          泛型的本質(zhì)是參數(shù)化類型,也就是說所操作的數(shù)據(jù)類型被指定為一個參數(shù)。

          | 泛型帶來的好處

          在沒有泛型的情況的下,通過對類型 Object 的引用來實現(xiàn)參數(shù)的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉(zhuǎn)換,而這種轉(zhuǎn)換是要求開發(fā)者對實際參數(shù)類型可以預(yù)知的情況下進行的。對于強制類型轉(zhuǎn)換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現(xiàn)異常,這是本身就是一個安全隱患。

          那么泛型的好處就是在編譯的時候能夠檢查類型安全,并且所有的強制轉(zhuǎn)換都是自動和隱式的。

          public?class?GlmapperGeneric<T>?{
          ??private?T?t;
          ????public?void?set(T?t)?{?this.t?=?t;?}
          ????public?T?get()?{?return?t;?}

          ????public?static?void?main(String[]?args)?{
          ????????//?do?nothing
          ????}

          ??/**
          ????*?不指定類型
          ????*/

          ??public?void?noSpecifyType(){
          ????GlmapperGeneric?glmapperGeneric?=?new?GlmapperGeneric();
          ????glmapperGeneric.set("test");
          ????//?需要強制類型轉(zhuǎn)換
          ????String?test?=?(String)?glmapperGeneric.get();
          ????System.out.println(test);
          ??}

          ??/**
          ????*?指定類型
          ????*/

          ??public?void?specifyType(){
          ????GlmapperGeneric?glmapperGeneric?=?new?GlmapperGeneric();
          ????glmapperGeneric.set("test");
          ????//?不需要強制類型轉(zhuǎn)換
          ????String?test?=?glmapperGeneric.get();
          ????System.out.println(test);
          ??}
          }

          上面這段代碼中的 specifyType 方法中 省去了強制轉(zhuǎn)換,可以在編譯時候檢查類型安全,可以用在類,方法,接口上。

          |?泛型中通配符

          我們在定義泛型類,泛型方法,泛型接口的時候經(jīng)常會碰見很多不同的通配符,比如 T,E,K,V 等等,這些通配符又都是什么意思呢?

          常用的 T,E,K,V,?

          本質(zhì)上這些個都是通配符,沒啥區(qū)別,只不過是編碼時的一種約定俗成的東西。比如上述代碼中的 T ,我們可以換成 A-Z 之間的任何一個 字母都可以,并不會影響程序的正常運行,但是如果換成其他的字母代替 T ,在可讀性上可能會弱一些。通常情況下,T,E,K,V,?是這樣約定的:

          • ?表示不確定的 java 類型
          • T (type) 表示具體的一個java類型
          • K V (key value) 分別代表java鍵值中的Key Value
          • E (element) 代表Element

          ?無界通配符

          先從一個小例子看起?。

          我有一個父類 Animal 和幾個子類,如狗、貓等,現(xiàn)在我需要一個動物的列表,我的第一個想法是像這樣的:

          List?listAnimals

          但是老板的想法確實這樣的:

          List?listAnimals

          為什么要使用通配符而不是簡單的泛型呢?通配符其實在聲明局部變量時是沒有什么意義的,但是當你為一個方法聲明一個參數(shù)時,它是非常重要的。

          static?int?countLegs?(List?animals?)?{
          ????int?retVal?=?0;
          ????for?(?Animal?animal?:?animals?)
          ????{
          ????????retVal?+=?animal.countLegs();
          ????}
          ????return?retVal;
          }

          static?int?countLegs1?(List?animals?){
          ????int?retVal?=?0;
          ????for?(?Animal?animal?:?animals?)
          ????{
          ????????retVal?+=?animal.countLegs();
          ????}
          ????return?retVal;
          }

          public?static?void?main(String[]?args)?{
          ????List?dogs?=?new?ArrayList<>();
          ??//?不會報錯
          ????countLegs(?dogs?);
          ?//?報錯
          ????countLegs1(dogs);
          }

          當調(diào)用 countLegs1 時,就會飄紅,提示的錯誤信息如下:

          所以,對于不確定或者不關(guān)心實際要操作的類型,可以使用無限制通配符(尖括號里一個問號,即 ),表示可以持有任何類型。像 countLegs 方法中,限定了上界,但是不關(guān)心具體類型是什么,所以對于傳入的 Animal 的所有子類都可以支持,并且不會報錯。而 countLegs1 就不行。

          上界通配符 < ? extends E>

          上屆:用 extends 關(guān)鍵字聲明,表示參數(shù)化的類型可能是所指定的類型,或者是此類型的子類。

          在類型參數(shù)中使用 extends 表示這個泛型中的參數(shù)必須是 E 或者 E 的子類,這樣有兩個好處:

          • 如果傳入的類型不是 E 或者 E 的子類,編譯不成功
          • 泛型中可以使用 E 的方法,要不然還得強轉(zhuǎn)成 E 才能使用
          private??E?test(K?arg1,?E?arg2){
          ????E?result?=?arg2;
          ????arg2.compareTo(arg1);
          ????//.....
          ????return?result;
          }

          類型參數(shù)列表中如果有多個類型參數(shù)上限,用逗號分開

          下界通配符 < ? super E>

          下界: 用 super 進行聲明,表示參數(shù)化的類型可能是所指定的類型,或者是此類型的父類型,直至 Object

          在類型參數(shù)中使用 super 表示這個泛型中的參數(shù)必須是 E 或者 E 的父類。

          private??void?test(Listsuper?T>?dst,?List?src){
          ????for?(T?t?:?src)?{
          ????????dst.add(t);
          ????}
          }

          public?static?void?main(String[]?args)?{
          ????List?dogs?=?new?ArrayList<>();
          ????List?animals?=?new?ArrayList<>();
          ????new?Test3().test(animals,dogs);
          }
          //?Dog?是?Animal?的子類
          class?Dog?extends?Animal?{

          }

          dst 類型 “大于等于” src 的類型,這里的“大于等于”是指 dst 表示的范圍比 src 要大,因此裝得下 dst 的容器也就能裝 src 。

          ?和 T 的區(qū)別

          ?和 T 都表示不確定的類型,區(qū)別在于我們可以對 T 進行操作,但是對 ?不行,比如如下這種 :

          //?可以
          T?t?=?operate();

          //?不可以
          ?car = operate();

          簡單總結(jié)下:

          T 是一個 確定的 類型,通常用于泛型類和泛型方法的定義,?是一個 不確定 的類型,通常用于泛型方法的調(diào)用代碼和形參,不能用于定義類和泛型方法。

          區(qū)別1:通過 T 來 確保 泛型參數(shù)的一致性

          //?通過?T?來?確保?泛型參數(shù)的一致性
          public??void
          test(List?dest,?List?src)

          //通配符是?不確定的,所以這個方法不能保證兩個?List?具有相同的元素類型
          public?void
          test(List?dest,?List?src)

          像下面的代碼中,約定的 T 是 Number 的子類才可以,但是申明時是用的 String ,所以就會飄紅報錯。

          不能保證兩個 List 具有相同的元素類型的情況

          GlmapperGeneric?glmapperGeneric?=?new?GlmapperGeneric<>();
          List?dest?=?new?ArrayList<>();
          List?src?=?new?ArrayList<>();
          glmapperGeneric.testNon(dest,src);

          上面的代碼在編譯器并不會報錯,但是當進入到 testNon 方法內(nèi)部操作時(比如賦值),對于 dest 和 src 而言,就還是需要進行類型轉(zhuǎn)換。

          區(qū)別2:類型參數(shù)可以多重限定而通配符不行

          使用 & 符號設(shè)定多重邊界(Multi Bounds),指定泛型類型 T 必須是 MultiLimitInterfaceA 和 MultiLimitInterfaceB 的共有子類型,此時變量 t 就具有了所有限定的方法和屬性。對于通配符來說,因為它不是一個確定的類型,所以不能進行多重限定。

          區(qū)別3:通配符可以使用超類限定而類型參數(shù)不行

          類型參數(shù) T 只具有 一種 類型限定方式:

          T?extends?A

          但是通配符 ? 可以進行 兩種限定:

          ??extends?A
          ??super?A

          | Class和?Class區(qū)別

          前面介紹了 ?和 T 的區(qū)別,那么對于,Class和?又有什么區(qū)別呢?Class和?Class

          最常見的是在反射場景下的使用,這里以用一段發(fā)射的代碼來說明下。

          //?通過反射的方式生成??multiLimit
          //?對象,這里比較明顯的是,我們需要使用強制類型轉(zhuǎn)換
          MultiLimit?multiLimit?=?(MultiLimit)
          Class.forName("com.glmapper.bridge.boot.generic.MultiLimit").newInstance();

          對于上述代碼,在運行期,如果反射的類型不是 MultiLimit 類,那么一定會報 java.lang.ClassCastException 錯誤。

          對于這種情況,則可以使用下面的代碼來代替,使得在在編譯期就能直接 檢查到類型的問題:

          Class在實例化的時候,T 要替換成具體類。Class它是個通配泛型,? 可以代表任何類型,所以主要用于聲明時的限制情況。比如,我們可以這樣做申明:

          //?可以
          public?Class?clazz;
          //?不可以,因為?T?需要指定類型
          public?Class?clazzT;

          所以當不知道定聲明什么類型的 Class 的時候可以定義一 個Class

          那如果也想?public Class clazzT;這樣的話,就必須讓當前的類也指定 T ,

          public?class?Test3<T>?{
          ????public?Class?clazz;
          ????//?不會報錯
          ????public?Class?clazzT;

          | 小結(jié)

          本文零碎整理了下 JAVA 泛型中的一些點,不是很全,僅供參考。如果文中有不當?shù)牡胤剑瑲g迎指正。

          往期推薦

          推薦:Spring Cloud 整合 Nacos 實現(xiàn)服務(wù)配置中心

          二十年老程序員的二十條心得:警惕很久沒寫過代碼的“大牛”

          “永遠的神 YYDS”,其創(chuàng)造者被判刑 3 年

          在互聯(lián)網(wǎng)上班,一定要知道勞動法這些....

          MyBatis-plus 快速入門

          Java 泛型通配符詳解


          END



          若覺得文章對你有幫助,隨手轉(zhuǎn)發(fā)分享,也是我們繼續(xù)更新的動力。


          長按二維碼,掃掃關(guān)注哦

          ?「C語言中文網(wǎng)」官方公眾號,關(guān)注手機閱讀教程??


          學習資料包括:?Java,算法,數(shù)據(jù)庫,Linux,簡歷,運維?等編程分類,在不斷更新中哦


          點擊“閱讀原文”,馬上免費領(lǐng)取!
          ??????
          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩一级在线看 | 欧美成人三级片网站 | 大香蕉综合第一页 | 久久精品熟女亚洲AV蜜桃 | 午夜三级福利无码 |