日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
詳解Java泛型type體系整理

一直對jdk的ref使用比較模糊,早上花了點時間簡單的整理了下,也幫助自己理解一下泛型的一些處理。

高臺網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)公司!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站設(shè)計等網(wǎng)站項目制作,到程序開發(fā),運營維護(hù)。創(chuàng)新互聯(lián)公司公司2013年成立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)公司

java中class,method,field的繼承體系

java中所有對象的類型定義類Type

說明:

Type : Type is the common superinterface for all types in the Java programming language. These include raw types, parameterized types, array types, type variables and primitive types.

使用

一般我們不直接操作Type類型,所以第一次使用會對這個比較陌生,相對內(nèi)部的一些概念。

根據(jù)Type類型分類,整理了一個type -> class的轉(zhuǎn)換過程,同理也包括處理Generic Type。支持多級泛型處理。

Java代碼

 
 
 
 
  1. private static Class  getClass(Type type, int i) {     
  2.         if (type instanceof ParameterizedType) { // 處理泛型類型     
  3.             return getGenericClass((ParameterizedType) type, i);     
  4.         } else if (type instanceof TypeVariable) {     
  5.             return (Class ) getClass(((TypeVariable) type).getBounds()[0], 0); // 處理泛型擦拭對象      
  6.         } else {// class本身也是type,強制轉(zhuǎn)型     
  7.             return (Class ) type;     
  8.         }     
  9.     }     
  10.     
  11.     private static Class  getGenericClass(ParameterizedType parameterizedType, int i) {     
  12.         Object genericClass = parameterizedType.getActualTypeArguments()[i];     
  13.         if (genericClass instanceof ParameterizedType) { // 處理多級泛型     
  14.             return (Class ) ((ParameterizedType) genericClass).getRawType();     
  15.         } else if (genericClass instanceof GenericArrayType) { // 處理數(shù)組泛型     
  16.             return (Class ) ((GenericArrayType) genericClass).getGenericComponentType();     
  17.         } else if (genericClass instanceof TypeVariable) { // 處理泛型擦拭對象      
  18.             return (Class ) getClass(((TypeVariable) genericClass).getBounds()[0], 0);     
  19.         } else {     
  20.             return (Class ) genericClass;     
  21.         }     
  22.     }    

測試代碼:

Java代碼

 
 
 
 
  1. interface GeneircInteface  {     
  2.     
  3.     T method1(T obj);     
  4. }     
  5.     
  6. interface CommonInteface {     
  7.     
  8.     Integer method2(Integer obj);     
  9. }     
  10.     
  11. class BaseGeneircInteface   implements GeneircInteface  {     
  12.     
  13.     protected R result;     
  14.     
  15.     @Override    
  16.     public R method1(R obj) {     
  17.         return obj;     
  18.     }     
  19.     
  20. }     
  21.     
  22. class GenericClass extends BaseGeneircInteface >  implements GeneircInteface >, CommonInteface {     
  23.     
  24.     @Override    
  25.     public List  method1(List  obj) {     
  26.         result = obj;     
  27.         return result;     
  28.     }     
  29.     
  30.     public Integer method2(Integer obj) {     
  31.         return obj;     
  32.     }     
  33.     
  34.     public  extends Throwable> T method3(T obj) throws E {     
  35.         return obj;     
  36.     }     
  37.     
  38. }    

針對class的泛型接口使用:

Java代碼

 
 
 
 
  1. private static void classGeneric() {     
  2.         System.out.println("\n--------------------- classGeneric ---------------------");     
  3.         GenericClass gc = new GenericClass();     
  4.         Type[] gis = gc.getClass().getGenericInterfaces(); // 接口的泛型信息     
  5.         Type gps = gc.getClass().getGenericSuperclass(); // 父類的泛型信息     
  6.         TypeVariable [] gtr = gc.getClass().getTypeParameters(); // 當(dāng)前接口的參數(shù)信息     
  7.         System.out.println("============== getGenericInterfaces");     
  8.         for (Type t : gis) {     
  9.             System.out.println(t + " : " + getClass(t, 0));     
  10.         }     
  11.         System.out.println("============== getGenericSuperclass");     
  12.         System.out.println(getClass(gps, 0));     
  13.         System.out.println("============== getTypeParameters");     
  14.         for (TypeVariable t : gtr) {     
  15.             StringBuilder stb = new StringBuilder();     
  16.             for (Type tp : t.getBounds()) {     
  17.                 stb.append(tp + " : ");     
  18.             }     
  19.     
  20.             System.out.println(t + " : " + t.getName() + " : " + stb);     
  21.         }     
  22.     
  23.     }    

針對method的泛型接口使用:

Java代碼

 
 
 
 
  1. private static void methodGeneric() throws Exception {     
  2.         System.out.println("\n--------------------- methodGeneric ---------------------");     
  3.         GenericClass gc = new GenericClass();     
  4.         Method method3 = gc.getClass().getDeclaredMethod("method3", new Class[] { Object.class });     
  5.     
  6.         Type[] gpt3 = method3.getGenericParameterTypes();     
  7.         Type[] get3 = method3.getGenericExceptionTypes();     
  8.         Type gt3 = method3.getGenericReturnType();     
  9.         System.out.println("============== getGenericParameterTypes");     
  10.         for (Type t : gpt3) {     
  11.             System.out.println(t + " : " + getClass(t, 0));     
  12.         }     
  13.         System.out.println("============== getGenericExceptionTypes");     
  14.         for (Type t : get3) {     
  15.             System.out.println(t + " : " + getClass(t, 0));     
  16.         }     
  17.         System.out.println("============== getType");     
  18.         System.out.println(gt3 + " : " + getClass(gt3, 0));     
  19.     }    

針對field的泛型接口使用:

Java代碼

 
 
 
 
  1. private static void fieldGeneric() throws Exception {     
  2.         System.out.println("\n--------------------- fieldGeneric ---------------------");     
  3.         GenericClass gc = new GenericClass();     
  4.         Field field = gc.getClass().getSuperclass().getDeclaredField("result");     
  5.     
  6.         Type gt = field.getGenericType();     
  7.         Type ft = field.getType();     
  8.         System.out.println("============== getGenericType");     
  9.         System.out.println(gt + " : " + getClass(gt, 0));     
  10.         System.out.println("============== getType");     
  11.         System.out.println(ft + " : " + getClass(ft, 0));     
  12.     }    

輸出結(jié)果:

Java代碼

 
 
 
 
  1. --------------------- classGeneric ---------------------     
  2. ============== getGenericInterfaces     
  3. com.agapple.misc.GeneircInteface > :  interface java.util.List     
  4. interface com.agapple.misc.CommonInteface : interface com.agapple.misc.CommonInteface     
  5. ============== getGenericSuperclass     
  6. interface java.util.List     
  7. ============== getTypeParameters     
  8.     
  9. --------------------- fieldGeneric ---------------------     
  10. ============== getGenericType     
  11. R : class java.lang.Object     
  12. ============== getType     
  13. class java.lang.Object : class java.lang.Object     
  14.     
  15. --------------------- methodGeneric ---------------------     
  16. ============== getGenericParameterTypes     
  17. T : class java.lang.Object     
  18. ============== getGenericExceptionTypes     
  19. E : class java.lang.Throwable     
  20. ============== getType     
  21. T : class java.lang.Object   

結(jié)果說明:

因為泛型的擦拭,對應(yīng)的GeneircInteface和BaseGeneircInteface,在源碼信息已被擦除對應(yīng)的類型,進(jìn)行了upper轉(zhuǎn)型,所以取到的是Object??梢允褂胑xtends

GenericClass在類定義時,聲明了繼承父接口的泛型為List,所以再通過接口和父類獲取泛型信息時,是能正確的獲取。通過javap -v可以獲取對應(yīng)的class信息

Java代碼

 
 
 
 
  1. const #46 = Asciz   Lcom/agapple/misc/BaseGeneircInteface ;>;Lcom/agapple/misc/GeneircInteface ;>;Lcom/agapple/misc/CommonInteface;;     

而在GenericClass中定義的方法method3,在class信息是一個被向上轉(zhuǎn)型后擦拭的信息。所以獲取method3的相關(guān)泛型信息是沒有的。

Java代碼

 
 
 
 
  1. method3;     
  2. const #36 = Asciz   (Ljava/lang/Object;)Ljava/lang/Object;;     
  3. const #37 = Asciz   Exceptions;     
  4. const #38 = class   #39;    //  java/lang/Throwable     
  5. const #39 = Asciz   java/lang/Throwable;     
  6. const #40 = Asciz    (TT;)TT;^TE;;     
  7. const #41 = Asciz   TT;;    

思考問題:

List list = new ArrayList(); 是否有獲取對應(yīng)的String泛型信息? 不能,臨時變量不能保存泛型信息到具體class對象中,List和List對應(yīng)的class實體是同一個。

Java代碼

 
 
 
 
  1. GeneircInteface gi = new GeneircInteface () {     
  2.     
  3.             @Override    
  4.             public Integer method1(Integer obj) {     
  5.                 return 1;     
  6.             }     
  7.     
  8.         };    

通過匿名類的方式,是否可以獲取Integer的泛型信息? 能,匿名類也會在進(jìn)行class compiler保存泛型信息。

假如本文例子中的method3,是放在父類中BaseGeneircInteface中進(jìn)行申明,GenericClass中指定R為List,是否可以獲取到對應(yīng)的泛型信息? 不能,理由和問題1類似。

備注

具體泛型擦拭和信息保存,引用了撒迦的一段回復(fù),解釋的挺詳盡了。

RednaxelaFX 寫道

Java泛型有這么一種規(guī)律:

位于聲明一側(cè)的,源碼里寫了什么到運行時就能看到什么;

位于使用一側(cè)的,源碼里寫什么到運行時都沒了。

什么意思呢?“聲明一側(cè)”包括泛型類型(泛型類與泛型接口)聲明、帶有泛型參數(shù)的方法和域的聲明。注意局部變量的聲明不算在內(nèi),那個屬于“使用”一側(cè)。

Java代碼

 
 
 
 
  1. import java.util.List;      
  2. import java.util.Map;      
  3.     
  4. public class GenericClass  {  // 1      
  5. private List  list;  // 2      
  6. private Map  map;  // 3      
  7.     
  8. public  U genericMethod(Map  m) {  // 4      
  9. return null;      
  10. }      
  11. }     

上面代碼里,帶有注釋的行里的泛型信息在運行時都還能獲取到,原則是源碼里寫了什么運行時就能得到什么。針對1的GenericClass,運行時通過Class.getTypeParameters()方法得到的數(shù)組可以獲取那個“T”;同理,2的T、3的java.lang.String與T、4的T與U都可以獲得。

這是因為從Java 5開始class文件的格式有了調(diào)整,規(guī)定這些泛型信息要寫到class文件中。以上面的map為例,通過javap來看它的元數(shù)據(jù)可以看到記錄了這樣的信息:

Javap代碼

  
 
 
 
  1. private java.util.Map map;      
  2. Signature: Ljava/util/Map;      
  3. Signature: length = 0x2      
  4. 00 0A     

乍一看,private java.util.Map map;不正好顯示了它的泛型類型被擦除了么?

但仔細(xì)看會發(fā)現(xiàn)有兩個Signature,下面的一個有兩字節(jié)的數(shù)據(jù),0x0A。到常量池找到0x0A對應(yīng)的項,是:

Javap代碼

  
 
 
 
  1. const #10 = Asciz Ljava/util/Map ;;    

也就是內(nèi)容為“Ljava/util/Map;”的一個字符串。

根據(jù)Java 5開始的新class文件格式規(guī)范,方法與域的描述符增添了對泛型信息的記錄,用一對尖括號包圍泛型參數(shù),其中普通的引用類型用“La/b/c/D;”的格式記錄,未綁定值的泛型變量用“Txxx;”的格式記錄,其中xxx就是源碼中聲明的泛型變量名。類型聲明的泛型信息也以類似下面的方式記了下來:

Javap代碼

  
 
 
 
  1. public class GenericClass extends java.lang.Object      
  2. Signature: length = 0x2      
  3. 00 12      
  4. // ...      
  5. const #18 = Asciz  Ljava/lang/Object;;    

詳細(xì)信息請參考官方文檔:http://java.sun.com/docs/books/jvms/second_edition/ClassFileFormat-Java5.pdf

相比之下,“使用一側(cè)”的泛型信息則完全沒有被保留下來,在Java源碼編譯到class文件后就確實丟失了。也就是說,在方法體內(nèi)的泛型局部變量、泛型方法調(diào)用之類的泛型信息編譯后都消失了。

Java代碼

  
 
 
 
  1. import java.util.ArrayList;      
  2. import java.util.List;      
  3.     
  4. public class TestClass {      
  5. public static void main(String[] args) {      
  6. List  list =  null; // 1      
  7. list = new ArrayList ();  // 2      
  8. for (int i = 0; i < 10; i++) ;      
  9. }      
  10. }   

上面代碼中,1留下的痕跡是:main()方法的StackMapTable屬性里可以看到:

Java代碼

  
 
 
 
  1. StackMapTable: number_of_entries = 2      
  2. frame_type = 253 /* append */      
  3. offset_delta = 12      
  4. locals = [ class java/util/List, int ]      
  5. frame_type = 250 /* chop */      
  6. offset_delta = 11     

但這里是沒有留下泛型信息的。這段代碼只所以寫了個空的for循環(huán)就是為了迫使javac生成那個StackMapTable,讓1多留個影。

如果main()里用到了list的方法,那么那些方法調(diào)用點上也會留下1的痕跡,例如如果調(diào)用list.add("");,則會留下“java/util/List.add:(Ljava/lang/Object;)Z”這種記錄。

2留下的是“java/util/ArrayList."":()V”,同樣也丟失了泛型信息。

由上述討論可知,想對帶有未綁定的泛型變量的泛型類型獲取其實際類型是不現(xiàn)實的,因為class文件里根本沒記錄實際類型的信息。覺得這句話太拗口的話用例子來理解:要想對java.util.List獲取E的實際類型是不現(xiàn)實的,因為List.class文件里只記錄了E,卻沒記錄使用List時E的實際類型。

想對局部變量等“使用一側(cè)”的已綁定的泛型類型獲取其實際類型也不現(xiàn)實,同樣是因為class文件中根本沒記錄這個信息。例子直接看上面講“使用一側(cè)”的就可以了。

知道了什么信息有記錄,什么信息沒有記錄之后,也就可以省點力氣不去糾結(jié)“拿不到T的實際類型”、“建不出T類型的數(shù)組”之類的問題了orz


當(dāng)前文章:詳解Java泛型type體系整理
標(biāo)題路徑:http://m.5511xx.com/article/codgepo.html