【譯】9. Java反射——泛型

pengisgood發表於2013-09-20

原文地址:http://tutorials.jenkov.com/java-reflection/generics.html

========================================================================================

     我經常在一些文章和論壇中看有人說Java泛型資訊都會在編譯時被擦除,所以你不能在執行時訪問任何相關的資訊。這也不完全對。在執行時,在少數情況下也是可以訪問到泛型資訊的。實際上,這些情況中已經滿足了我們對Java泛型資訊的需求。本文將解釋這幾種情況。
     下面是本文所涵蓋的主題列表:

  1. The Generics Reflection Rule of Thumb ()
  2. Generic Method Return Type (方法返回值型別的泛型)
  3. Generic Method Parameter Types (方法引數型別的泛型)
  4. Generic Field Types (欄位型別的泛型)

========================================================================================

  • The Generics Reflection Rule of Thumb

     使用Java泛型無外乎就下面兩種情況中的一種:

  1. Declaring a class/interface as being parameterizable. (宣告類、介面引數化)
  2. Using a parameterizable class.(使用引數化的類)

     當你寫一個類或者介面的時候,你可以指定它可以被引數化。java.util.List介面就是這種用法。你可以使java.util.List引數化的建立一個String的列表,而不是建立一個Object的列表。
     當在執行時檢查引數化型別它自己的型別時,如java.util.List,沒有辦法知道它具體被引數化成了什麼型別。這樣也合理,因為在同一應用程式中引數化的型別可以是所有型別。但是,當你檢查用引數化型別宣告的方法或者欄位時,你可以知道它們在執行時引數化成了什麼型別。簡而言之:
     在執行時,你不會知道引數化型別它自己的型別,但是你能知道用了引數化型別的欄位和方法的型別。換句話說,它們有具體的引數型別。
     下面的部分我們將更進一步的來看這幾種情況。
========================================================================================

  • Generic Method Return Types

     如果你獲得了java.lang.reflect.Method物件,你也是有可能獲得它的返回值型別的泛型資訊的。這不會是任何引數化型別的Method物件,除了在類裡面使用了引數化型別。你可以去看“Java泛型:方法”來了解如何獲取Method物件。下面是一個例子,類中有引數化返回值型別的返回值:

public class MyClass {
  protected List<String> stringList = ...;
  public List<String> getStringList(){
    return this.stringList;
  }
}

     在這種情況下,可以取得getStringList()方法的泛型返回值型別。換句話說,是可以檢測到getStringList()方法返回的是List<String>型別而不僅僅是List。下面是如何來取:

Method method = MyClass.class.getMethod("getStringList", null);
Type returnType = method.getGenericReturnType();
if(returnType instanceof ParameterizedType){
    ParameterizedType type = (ParameterizedType) returnType;
    Type[] typeArguments = type.getActualTypeArguments();
    for(Type typeArgument : typeArguments){
        Class typeArgClass = (Class) typeArgument;
        System.out.println("typeArgClass = " + typeArgClass);
    }
}

     這段程式碼將會列印出“typeArgClass = java.lang.String”.Type[ ]型別的陣列typeArguements中包含一個項——一個代表實現了Type介面的java.lang.String.Class的Class例項。

========================================================================================

  • Generic Method Parameter Types

     在執行時,你也可以用Java反射機制訪問泛型引數的型別。下面是一個例子,類裡面有一個引數化型別的引數:

public class MyClass {
  protected List<String> stringList = ...;
  public void setStringList(List<String> list){
    this.stringList = list;
  }
}

     你可以像這樣來訪問其方法引數的引數化型別:

method = Myclass.class.getMethod("setStringList", List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for(Type genericParameterType : genericParameterTypes){
    if(genericParameterType instanceof ParameterizedType){
        ParameterizedType aType = (ParameterizedType) genericParameterType;
        Type[] parameterArgTypes = aType.getActualTypeArguments();
        for(Type parameterArgType : parameterArgTypes){
            Class parameterArgClass = (Class) parameterArgType;
            System.out.println("parameterArgClass = " + parameterArgClass);
        }
    }
}

     這段程式碼將會列印出“parameterArgType = java.lang.String”。Type[ ]型別的陣列parameterArgTypes中包含一個項——一個代表實現了Type介面的java.lang.String.Class的Class例項。

========================================================================================

  • Generic Field Types

     也可以訪問公有欄位的泛型型別。欄位是類的成員變數——要麼是靜態變數,要麼是實體變數。你可以去看“Java泛型:欄位”來了解如何獲取Field物件。下面是一個很早之前的例子,類中有有一個叫stringList的實體欄位:

public class MyClass {
  public List<String> stringList = ...;
}
Field field
= MyClass.class.getField("stringList"); Type genericFieldType = field.getGenericType(); if(genericFieldType instanceof ParameterizedType){ ParameterizedType aType = (ParameterizedType) genericFieldType; Type[] fieldArgTypes = aType.getActualTypeArguments(); for(Type fieldArgType : fieldArgTypes){ Class fieldArgClass = (Class) fieldArgType; System.out.println("fieldArgClass = " + fieldArgClass); } }

     這段程式碼將會列印出“fieldArgClass = java.lang.String”。Type[ ]型別的fieldArgTypes陣列中包含一個項——一個代表實現了Type介面的java.lang.String.Class的Class例項。

 

 ========================================================================================

 

  • 目錄

 

  這是一個本教程到目前為止涵蓋的主題列表:     

 

  1. Java反射——引言
  2. Java反射——Class物件
  3. Java反射——建構函式
  4. Java反射——欄位
  5. Java反射——方法
  6. Java反射——Getter和Setter
  7. Java反射——私有欄位和私有方法
  8. Java反射——註解
  9. Java反射——泛型
  10. Java反射——陣列
  11. Java反射——動態代理
  12. Java反射——類的動態載入和重新載入

 

(敬請期待下一篇翻譯)

 

 

 

相關文章