Java反射-範型

我常常在文章或論壇中讀到全部的Java範型信息都會在編譯時搽除,因此不能在運行時訪問範型的任何信息。這並不徹底準確。某些案例下能夠在運行時訪問範型信息,這些案例實際上覆蓋了咱們對範型信息的一些需求。本文將解釋這些案例。html

範型反射的使用法則

使用範型一般有2種不一樣的場景:java

  1. 定義一個可參數化的類/接口
  2. 使用可參數化的類

當你編寫一個類/接口時,能夠指定類/接口是否被參數化。這是java.util.List接口的示例。你能夠參數化java.util.List接口去建立一個String類型的list,而不是object list,以下:數組

List<String> myList = new ArrayList<String>();

當使用反射檢視可參數化類型自己時,好比java.util.List,是沒有辦法獲得它的已參數化的類型的。object自身是不知道它參數化的類型的。
然而,object的reference知道它包含的範型引用的類型信息。那就是,若是它不是局部變量。若是一個object被另外一個object的field引用,你就能夠經過反射查看Field定義,經過field得到範型的類型信息。
同理,若是一個object被一個方法的參數引用。能夠經過方法的Parameter,你能夠看到方法參數肯定範型的類型信息。
最後,你能夠經過方法返回值肯定反射範型信息。須要強調的是,實際返回object時你不能獲得範型信息。你須要經過反射查看方法定義,去得到方法定義的返回值(包含範型信息)。
總結起來就是:你只能經過object的引用查看它的範型信息,而不能經過它自身查看。
下面的部分將仔細研究這些狀況。學習

方法返回範型類型

如你已得到java.lang.reflect.Method對象,那麼就能夠得到它的返回值的範型。你能夠閱讀 "Java Generics: Methods"學習如何得到Method對象。下面示例類的方法擁有一個可參數化的返回類型。this

public class MyClass {

  protected List<String> stringList = ...;

  public List<String> getStringList(){
    return this.stringList;
  }
}

在這個類中能夠得到方法getStringList()的帶範型的返回類型。換言之,能夠發現方法getStringList()返回List<String>並不單單是List。代碼以下:code

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[]數組typeArguments包含單個元素-java.lang.String類的Class實例。Class實現了Type接口。htm

方法參數是範型類型

你也能夠在運行時經過反射訪問方法的範型參數。下面示例類有一個方法擁有一個參數化List做爲參數:對象

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包含單個元素-表明類java.lang.StringClass實例。Class實現了Type`接口。get

屬性是範型類型

一樣的,咱們也能夠訪問公共屬性的範型類型。屬性是類的成員變量-不管靜態或實例變量。你能夠得到關於Field的文章"Java Generics: Fields",下方是早些時候的示例代碼,擁有一個名爲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包含的單元素-表明java.lang.String類的Class實例。Class實現了Type接口。

相關文章
相關標籤/搜索