中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java泛型的概念和Type類型體系

發布時間:2021-09-16 18:23:03 來源:億速云 閱讀:118 作者:chen 欄目:編程語言

本篇內容主要講解“Java泛型的概念和Type類型體系”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java泛型的概念和Type類型體系”吧!

 1 JAVA的Type類型體系

先了解下java的Type類型體系(類的類=>類型),Type是所有類型(原生類型-Class、參數化類型-Parameterizedtype、數組類型-GenericArrayType、類型變量-TypeVariable、基本類型-Class)的共同接口;前兩篇反射和注解講到的Class就是Type的一實現類

Java泛型的概念和Type類型體系

  • Type下面又有四個子接口類ParameterizedType、TypeVariable、GenericArrayType、WildcardType

    • List

      表示泛型,E是TypeVariable類型,List則是ParameterizedType(參數化類型),List里的String稱為實際參數類型
    • 具體化泛型中的類型時,可以使用 ? extends 或 ? super來表示繼承關系;如List,而里面的 ?  稱為通配符類型WildcardType

    • GenericArrayType  表示一種元素類型是ParameterizedType(參數化類型)或者TypeVariable(類型變量)的數組類型,如T[] 或者 List

      []
  • 注解是JDK1.5才出現了的,為了表示被注解的類型的,加入AnnotatedElement類型,字面意思就是被注解的元素。JDK1.8又有了AnnotatedType將Type和被注解元素的概念關聯起來。

  • Java泛型的概念和Type類型體系

  • AnnotatedType也有四個子接口,和Type的四個子接口一一對應,如:ParameterizedType類型被注解則被編譯器解析成AnnotatedParameterizedType:  @AnTest("list")List

    list

2 泛型的概念

  • Java  泛型(generics)是JDK1.5中引入的一個新特性,其本質是參數化類型,解決不確定具體對象類型的問題;其所操作的數據類型被指定為一個參數(type  parameter)這種參數類型可以用在類、接口和方法的創建中,分別稱為泛型類、泛型接口、泛型方法

泛型: 把類型明確的工作推遲到創建對象或調用方法的時候才去明確的特殊的類型

3 泛型類和泛型方法的示例

  • 泛型類的定義

public class MainTest<T> {     private  T param; } public static void main(String[] args){         MainTest<String> data = new MainTest<String>(){};         ParameterizedType genType1 = (ParameterizedType)data.getClass().getGenericSuperclass();   }
  • 泛型方法的定義

public class MainTest{     public static void main(String[] args){         printData("siting");     }     static  <T> T printData(T t){         System.out.println(t);         return t;     } }

接口和抽象類都可以使用泛型

4 類型擦除

  • 創建泛型的實例時,jvm是會把具體類型擦除的;編譯生成的字節碼中不包含泛型中的類型參數,即ArrayList

    和ArrayList都擦除成了ArrayList,也就是被擦除成"原生類型",這就是泛型擦除
public class MainTest {     public static void main(String[] args){         List<String> strArr  = new ArrayList<>();         List<Integer> intArr  = new ArrayList<>();         Type strClazz = strArr.getClass();         Type intClazz = intArr.getClass();     } }

Java泛型的概念和Type類型體系

  • 查看編譯后的字節碼文件是如何表示的: idea菜單 -> view -> show ByteCode

public class MainTest<T> {     T param;     public static void main(String[] args){         MainTest<String> test = new MainTest<>();         test.setParam("siting");     }     public T getParam() {  return param;   }     public void setParam(T param) {  this.param = param;  } } public class com/MainTest {   ...省略   public static main([Ljava/lang/String;)V    L0     LINENUMBER 7 L0     NEW com/MainTest     DUP     INVOKESPECIAL com/MainTest.<init> ()V     ASTORE 1    L1     LINENUMBER 8 L1     ALOAD 1     LDC "siting"     // 調用類型擦除后的setParam(Object)     INVOKEVIRTUAL com/MainTest.setParam (Ljava/lang/Object;)V    L2    ...省略//getParam 的返回值是Object   public getParam()Ljava/lang/Object;    L0     LINENUMBER 10 L0     ALOAD 0     GETFIELD com/MainTest.param : Ljava/lang/Object;     ARETURN    ...省略//setParam 的入參是Object   public setParam(Ljava/lang/Object;)V    L0     LINENUMBER 11 L0     ALOAD 0     ALOAD 1     PUTFIELD com/MainTest.param : Ljava/lang/Object;     RETURN    ... }

可以看出T(String)都被轉換為Object類型,最初的初始化的String不見了

5 泛型的繼承

  • 子類可以指定父類的泛型參數,可以是已知類(Integer、String等),也可以用子類自己的泛型參數指定

  • 泛型被繼承時,且指定父類泛型參數,則額外生成的ParameterizedType類型作為子類的父類;如果沒有指定父類泛型參數,則直接繼承原生類型

public class MainTest<T> {     T param;     static public class SubTest1 extends MainTest<String>{}     static public class SubTest2<R> extends MainTest<R>{}     //SubTest3繼承的時原生類型     static public class SubTest3 extends MainTest{} }

Java泛型的概念和Type類型體系

6 泛型變量TypeVariable

  • (先臨時定義一個名稱,Test

    里的E為泛型參數);泛型變量TypeVariable:泛型的泛型參數就是TypeVariable;當父類使用子類的泛型參數指定自身的泛型參數時;或者泛型屬性定義在泛型類A中,并使用泛型類A的泛型參數T時,其泛型參數都會被編譯器定為泛型變量TypeVariable,而不是被擦除
public class MainTest<T> {     List<T> param;     public static void main(String[] args) throws Exception{         Class clazz =  MainTest.class;         TypeVariable[] typeVariable = clazz.getTypeParameters();         // 1         Field field = clazz.getDeclaredField("param");         ParameterizedType arrayType = (ParameterizedType)field.getGenericType();         // interface List<E> 的泛型類型E被T,具體化,因此其被識別為 TypeVariable         TypeVariable variable1 = (TypeVariable)arrayType.getActualTypeArguments()[0];         // 2         ParameterizedType type = (ParameterizedType)SubTest.class.getGenericSuperclass();         TypeVariable variable2 = (TypeVariable)type.getActualTypeArguments()[0];     }     static class SubTest<R> extends MainTest<R>{} }

7 參數化類型ParameterizedType

public interface ParameterizedType extends Type {     //獲取實際參數,List<String>里的String; 如果是List<T>則是TypeVariable類型     Type[] getActualTypeArguments();      // 獲取原始類型List<String> -> List<E>     Type getRawType();       Type getOwnerType(); }
  • 需要注意的點,我們不能直接獲取指定具體參數的泛型的類型,如Class clazz =  List

    .class編譯時不通過的;還有就是直接通過泛型類new創建的對象,其Class并非ParameterizedType類型,而是泛型本身的class,示例如下
public class MainTest<T> {     public static void main(String[] args){         MainTest<String> str = new MainTest<String>();         Class variable = str.getClass();         Type genType1 = variable.getGenericSuperclass();     } }

Java泛型的概念和Type類型體系

  • 被具體參數化的泛型才能被編譯器識別為ParameterizedType類型,有三種方式獲取ParameterizedType類型

// 1 子類繼承泛型時,指定具體參數(可以是String等已知類型,也可以是子類的泛型參數) // 2 獲取在類內部定義的泛型屬性,需指定具體泛型參數 // 3 局部代碼,可以通過泛型的匿名內部子類(需指定具體泛型參數)獲取ParameterizedType類型 public class MainTest<T> {     List<T> list;     public static void main(String[] args) throws NoSuchFieldException {         SubTest<String> str = new SubTest<>();         // 方式一         Class variable = str.getClass();         // 父類是(521)ParameterizedType類型         ParameterizedType genType = (ParameterizedType)variable.getGenericSuperclass();         // (521)ParameterizedType類型的原生類型是(479)class com.MainTest         Type clazz = genType.getRawType();         //MainTest.class 的原生類型是 (479)class com.MainTest         Class rawClazz = MainTest.class;          //方式二,泛型屬性         Field field = rawClazz.getDeclaredField("list");         //屬性list 類型是(546)ParameterizedType類型List<T>         ParameterizedType fieldType = (ParameterizedType)field.getGenericType();          // 方式三         MainTest<String> sub3 = new MainTest<String>(){};         // clazz3是匿名子類         Class clazz3 =  sub3.getClass();         //父類是(555)ParameterizedType類型         ParameterizedType genType3 = (ParameterizedType) clazz3.getGenericSuperclass();         // (555)ParameterizedType類型的原生類型是(479)class com.MainTest         Type type3 = genType3.getRawType();     }     public static class SubTest<R> extends MainTest<R>{ } }

Java泛型的概念和Type類型體系

8 通配符(WildcardType)

無邊界通配符:無界通配符 ? 可以適配任何引用類型:

  • 當方法參數需要傳入一個泛型時,而且無法確定其類型時。直接使用無具體泛型變量的泛型,容易造成安全隱患;若在方法代碼里進行類型轉換,極容易出現ClassCastException錯誤

  • 那泛型變量用Object代替不就行了?但是泛型類+具體參數轉變的ParameterizedType(參數化類型)是不存在繼承關系;即Object是String的父類,但是List  和List

    的類型是不同的兩個ParameterizedType,不存在繼承關系。于是有了類型通配符 ?
public static void print(List list){}  ----->>> public static void print(List<?> list){}

Java泛型的概念和Type類型體系

  • 無界通配符可以匹配任意類型;但是在使用?時,不能給泛型類的變量設置值,因為我們不知道具體類型是什么;如果強行設置新值,后面的讀容易出現ClassCastException錯誤。因此編譯器限制了**通配符  ?**的泛型只能讀不能寫

上界限定通配符 < ? extends E>

  • 想接收一個List集合,它只能操作數字類型的元素【Float、Integer、Double、Byte等數字類型都行】,怎么做?可以使用List,表明List里的元素都是Number的子類

  • public static void print(List<? extends Number> list) {         Number n = new Double("1.0");         list.add(n);         Number tmp = list.get(0);     }

Java泛型的概念和Type類型體系

  • 圖片里可以看出,存在上界通配符,因為具體類型不確定,也是只能讀不能寫的

下界限定通配符 < ? super E>

class Parent{ } class Child extends Parent{ } public class MainTest<T> {     T param;     public static void main(String[] args){         MainTest<? super Child> parent_m = new MainTest<>();         parent_m.setParam(new Child());         Object parent = parent_m.getParam();     }     public T getParam() {  return param;  }     public void setParam(T param) {  this.param = param; } }

Java泛型的概念和Type類型體系

  • 如果定義了通配符是誰的父類,則是下界限定通配符;此類通配符可讀可寫,轉成任意父類都不會出現ClassCastException錯誤。

  • 個人猜想:難道是因為通配符和上界限定通配符的泛型  向下轉型容易出現ClassCastException錯誤,而下界限定通配符向上轉型不會出現ClassCastException錯誤,因此java規范限制前者編譯出錯,而后面編譯通過?

9 泛型數組(GenericArrayType)

public interface GenericArrayType extends Type {     //獲得這個數組元素類型,即獲得:A<T>(A<T>[])或  T(T[])     Type getGenericComponentType(); }
  • GenericArrayType,泛型數組,描述的是ParameterizedType類型以及TypeVariable類型數組,即形如:Test

    [][]、T[]等,是GenericArrayType的子接口
public class MainTest<T> {     T[] param;     public static void main(String[] args) throws Exception{         Class clazz =  MainTest.class;         Field field = clazz.getDeclaredField("param");         GenericArrayType arrayType = (GenericArrayType)field.getGenericType();         TypeVariable variable = (TypeVariable) arrayType.getGenericComponentType();     } }

Java泛型的概念和Type類型體系

到此,相信大家對“Java泛型的概念和Type類型體系”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

察雅县| 富蕴县| 曲阳县| 英吉沙县| 农安县| 秦皇岛市| 桃园县| 禄丰县| 长岛县| 蓬莱市| 藁城市| 固始县| 托克逊县| 苍溪县| 镇巴县| 理塘县| 沛县| 平顶山市| 安塞县| 呼伦贝尔市| 耒阳市| 青河县| 榆中县| 三明市| 山东省| 合江县| 饶平县| 福州市| 交口县| 河东区| 辛集市| 天全县| 临朐县| 民权县| 灵丘县| 双流县| 福安市| 车险| 甘洛县| 苍南县| 饶平县|