隨筆-67  評論-522  文章-0  trackbacks-0
              前一篇對泛型進行了一番總結,本篇就來說說與泛型有關的反射。
              我在泛型篇中說到了泛型在JVM中是會被擦除的,不過擦除的類還是“殘留”了一些泛型的痕跡。比如Person<T>類,雖然擦除掉了泛型<T>,但是通過反射機制是可以獲得這些信息的,不光如此,Person類里面定義的泛型方法都可以通過反射獲得。讓我們用代碼來驗證一下。
              在用代碼驗證之前,大象會對Person類稍微改造一下,增加一個泛型變量K以及一個泛型方法,其它的都保持不變。
              public class Person<T, K extends Comparable<? super T> & Serializable>
                  extends SuperPerson<String> implements Handle<Date> {
                  ......
                  public static <T extends Comparable<? super T>> T max(List<? extends T> list){
                    Iterator<? extends T> it = list.iterator();
                      T result = it.next();
                      while(it.hasNext()){
                          T t = it.next();
                          if(t.compareTo(result) > 0)
                              result = t;
                      }
                      return result;
                  }
                  ......
              }
              下面可以開始寫代碼了嗎?別急,大象還想先把代碼中用到的幾個跟反射有關的API接口說明一下,這都是JDK5.0中為泛型新增的,然后還用到了一個JDK6.0提供的Modifier,它是一個枚舉類型,可以表示類、方法或字段的修飾符。
              Type
              它是所有類型的公共接口。包括原始類型、參數化類型、數組類型、類型變量和基本類型。ParameterizedType, TypeVariable, WildcardType,GenericArrayType這四個接口都是它的子接口。
              GenericDeclaration
              這個接口ClassMethodConstructor都有實現,我們就是要用這個接口的getTypeParameters方法,它返回一個TypeVariable[]數組,這個數組里面就是我們定義的類型變量TK,順序與我們聲明時一樣。如果用循環語句將數組打印出來,你會發現只會輸出TK,這可不是我們想要的結果,那么想要獲得預期的結果怎么辦呢?請繼續往下看。
              TypeVariable
              它表示類型變量。比如T,比如K extends Comparable<? super T> & Serializable,這個接口里面有個getBounds()方法,它用來獲得類型變量上限的Type數組,如果沒有定義上限,則默認設定上限為Object,請注意TypeVariable是接口,實際得到的是TypeVariableImpl實現類,下面幾個接口都一樣。
              TK來說明,T沒有定義任何上限,所以它就有一個默認上限java.lang.Object,實際跟蹤代碼的時候你會發現Tbounds屬性為空,只有在調用了getBounds()方法后,才會有一個Type[1]數組[class java.lang.Object]。而對于K來說,調用了getBounds方法后,得到的數組是[java.lang.Comparable<? super T>, interface java.io.Serializable],它們的類型卻是不一樣的,第1個是ParameterizedType,而第二個是Class
              ParameterizedType
              ParameterizedType表示參數化類型,就是上面說的java.lang.Comparable<? super T>,再比如List<T>List<String>,這些都叫參數化類型。得到Comparable<? super T>之后,再調用getRawType()getActualTypeArguments()兩個方法,就可以得到聲明此參數化類型的類(java.lang.Comparable)和實際的類型參數數組([? super T]),而這個? super T又是一個WildcardType類型。
              WildcardType
              它用來描述通配符表達式,上面返回的? super T正好是這個類型。然后調用getUpperBounds()上限和getLowerBounds()下限這兩個方法,獲得類型變量?的限定類型(上下限),對于本例的通配符(?),它的上限為java.lang.Object,下限為T
          通過上面幾個接口的分析,可以將Person類的泛型參數都解析出來,那么Person的超類以及實現的接口該怎么處理呢?Class類里面同樣在1.5版本加入了getGenericSuperclass()getGenericInterfaces()兩個方法,用于返回帶參數化類型的超類與接口。
              至此,通過上面這些接口和方法我們已經可以把class Person后面的代碼都解析出來了,類里面的方法與解析類的泛型化參數類似,就不再贅述了。下圖就是通過反射將定義的Person類打印出來的結果。
              
              本文主要是想通過反射機制來驗證在JVM虛擬機中獲得泛型的一些知識。一般實際使用的時候多數是通過反射獲取超類的泛型,或者通過反射調用方法,讀取/設置屬性值等等這些功能,最下面有示例源碼的下載。
              反射雖然很有用處,但也不能濫用。首先用了反射就沒辦法在編譯時進行類型檢查,而且反射的代碼比較復雜不容易閱讀,不過好在現在有很多已經封裝好的反射工具類,幫我們做了不少這方面的工作。最后也是最重要的一點是因為,使用反射會有一定的性能損耗,就是說會比直接調用方法要慢,至于慢多少,這個不好說,但肯定會慢,因此除非有必要,大象建議在一般情況下首先考慮用接口來代替反射。
              以上這些都是本篇關于泛型相關的反射介紹,算是一個入門知識吧,有什么不對的,或不完善的地方,還請各位指出來,謝謝!
              源碼下載: 泛型與反射 
              本文為菠蘿大象原創,如要轉載請注明出處。http://www.aygfsteel.com/bolo
          posted on 2014-05-06 14:33 菠蘿大象 閱讀(6147) 評論(1)  編輯  收藏 所屬分類: Java

          評論:
          # re: 泛型與反射的使用總結之反射篇 2014-05-23 15:45 | 王凱文
          略難 有點不太懂.  回復  更多評論
            
          主站蜘蛛池模板: 搜索| 信阳市| 越西县| 伊吾县| 布尔津县| 澄城县| 内乡县| 伊金霍洛旗| 柯坪县| 永泰县| 增城市| 双柏县| 阿瓦提县| 嘉兴市| 罗源县| 徐水县| 本溪市| 阳曲县| 和林格尔县| 钦州市| 和静县| 盐亭县| 峡江县| 泰来县| 大姚县| 和平县| 喀喇沁旗| 伊吾县| 闵行区| 湄潭县| 化隆| 清水县| 上饶县| 渭南市| 新巴尔虎右旗| 古浪县| 吉木萨尔县| 什邡市| 台北市| 鄂伦春自治旗| 武城县|