久久综合给合久久狠狠狠974色|亚洲成熟丰满熟妇高潮xxxxx|国产又黄又黄又大又粗又爽的视频|日韩久久久精品无码一区二区三区|中文字幕无码乱人伦一区二区三区|国产成人无码区免费内射一片色欲|亚洲av无码久久精品一区二区三区

                      Java 中的 T,E,K,V, 別傻傻分不清楚

                      2020-09-04 04:17:03  閱讀:-  來源:

                      前言

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

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

                      泛型帶來的好處

                      在沒有泛型的情況的下,通過對(duì)類型 Object 的引用來實(shí)現(xiàn)參數(shù)的“任意化”,“任意化”帶來的缺點(diǎn)是要做顯式的強(qiáng)制類型轉(zhuǎn)換,而這種轉(zhuǎn)換是要求開發(fā)者對(duì)實(shí)際參數(shù)類型可以預(yù)知的情況下進(jìn)行的。

                      對(duì)于強(qiáng)制類型轉(zhuǎn)換錯(cuò)誤的情況,編譯器可能不提示錯(cuò)誤,在運(yùn)行的時(shí)候才出現(xiàn)異常,這是本身就是一個(gè)安全隱患。

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

                      public

                      class

                      GlmapperGeneric
                      {

                      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"
                      );

                      // 需要強(qiáng)制類型轉(zhuǎn)換

                      String
                      test = (
                      String
                      ) glmapperGeneric.get();

                      System
                      .out.println(test);
                      }

                      /**
                      * 指定類型
                      */

                      public

                      void
                      specifyType(){

                      GlmapperGeneric
                      <
                      String
                      > glmapperGeneric =
                      new

                      GlmapperGeneric
                      ();
                      glmapperGeneric.set(
                      "test"
                      );

                      // 不需要強(qiáng)制類型轉(zhuǎn)換

                      String
                      test = glmapperGeneric.get();

                      System
                      .out.println(test);
                      }
                      }

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

                      泛型中通配符

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

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

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

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

                      ? 無界通配符

                      下面先從一個(gè)小例子看起:

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

                      List
                      <
                      Animal
                      > listAnimals

                      但是老板的想法確實(shí)這樣的:

                      List
                      extends

                      Animal
                      > listAnimals

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

                      static

                      int
                      countLegs (List animals ) {

                      int retVal = 0;

                      for ( Animal animal : animals )
                      {
                      retVal += animal.countLegs();
                      }

                      return retVal;
                      }
                      static

                      int
                      countLegs1 (
                      List< Animal > animals ){
                      int retVal = 0;
                      for ( Animal animal : animals ) {
                      retVal += animal.countLegs();
                      }

                      return retVal;
                      }
                      public static void main(String [] args) {
                      List dogs = new
                      ArrayList<>();

                      // 不會(huì)報(bào)錯(cuò)
                      countLegs( dogs );

                      // 報(bào)錯(cuò)
                      countLegs1(dogs);
                      }

                      當(dāng)調(diào)用 countLegs1 時(shí),就會(huì)飄紅,提示的錯(cuò)誤信息如下:

                      Java 中的 T,E,K,V, 別傻傻分不清楚

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

                      上界通配符 < ? extends E>

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

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

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

                      //.....

                      return
                      result;
                      }

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

                      下界通配符 < ? super E>

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

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

                      private

                      void
                      test(
                      List
                      super
                      T> dst,
                      List
                      src){

                      for
                      (T t : src) {
                      dst.add(t);
                      }
                      }
                      public

                      static

                      void
                      main(
                      String
                      [] args) {

                      List
                      <
                      Dog
                      > dogs =
                      new

                      ArrayList
                      <>();

                      List
                      <
                      Animal
                      > animals =
                      new

                      ArrayList
                      <>();

                      new

                      Test3
                      ().test(animals,dogs);
                      }
                      // Dog 是 Animal 的子類
                      class

                      Dog

                      extends

                      Animal
                      {
                      }

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

                      ?和 T 的區(qū)別

                      Java 中的 T,E,K,V, 別傻傻分不清楚

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

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

                      簡(jiǎn)單總結(jié)下:

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

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

                      // 通過 T 來 確保 泛型參數(shù)的一致性
                      public
                      extends

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

                      void
                      test(
                      List
                      extends

                      Number
                      > dest,
                      List
                      extends

                      Number
                      > src)

                      像下面的代碼中,約定的 T 是 Number 的子類才可以,但是申明時(shí)是用的 String ,所以就會(huì)飄紅報(bào)錯(cuò)。

                      Java 中的 T,E,K,V, 別傻傻分不清楚

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

                      GlmapperGeneric
                      glmapperGeneric = new

                      GlmapperGeneric
                      <>();
                      List

                      dest = new

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

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

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

                      Java 中的 T,E,K,V, 別傻傻分不清楚

                      使用 & 符號(hào)設(shè)定多重邊界(Multi Bounds),指定泛型類型 T 必須是 MultiLimitInterfaceA 和 MultiLimitInterfaceB 的共有子類型,此時(shí)變量 t 就具有了所有限定的方法和屬性。對(duì)于通配符來說,因?yàn)樗皇且粋€(gè)確定的類型,所以不能進(jìn)行多重限定。

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

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

                      T extends A

                      但是通配符 ? 可以進(jìn)行 兩種限定:

                      ? extends A
                      ? super A


                      Class 和 Class 區(qū)別

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

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

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

                      對(duì)于上述代碼,在運(yùn)行期,如果反射的類型不是 MultiLimit 類,那么一定會(huì)報(bào) java.lang.ClassCastException 錯(cuò)誤。

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

                      Java 中的 T,E,K,V, 別傻傻分不清楚

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

                      // 可以
                      public

                      Class
                      clazz;
                      // 不可以,因?yàn)?T 需要指定類型
                      public

                      Class
                      clazzT;

                      所以當(dāng)不知道定聲明什么類型的 Class 的時(shí)候可以定義一 個(gè)Class。

                      Java 中的 T,E,K,V, 別傻傻分不清楚

                      那如果也想 publicClassclazzT; 這樣的話,就必須讓當(dāng)前的類也指定 T ,

                      public

                      class

                      Test3
                      {

                      public

                      Class
                      clazz;

                      // 不會(huì)報(bào)錯(cuò)

                      public

                      Class
                      clazzT;
                      }
                      高邑县| 伊金霍洛旗| 吉安市| 兴义市| 庆云县| 汉源县| 上虞市| 江城| 江阴市| 林周县| 开江县| 改则县| 高碑店市| 巩义市| 宁强县| 萝北县| 五台县| 青田县| 鄂托克前旗| 伽师县| 宜章县| 信阳市| 尼玛县| 太湖县| 兖州市| 余姚市| 迁西县| 文登市| 东安县| 元谋县| 乌什县| 东乡族自治县| 伊川县| 抚远县| 遵义市| 宁明县| 嘉鱼县| 威远县| 邮箱| 石棉县| 江山市|