(翻譯)反射處理java泛型

當咱們聲明瞭一個泛型的接口或類,或須要一個子類繼承至這個泛型類,而咱們又但願利用反射獲取這些泛型參數信息。這就是本文將要介紹的ReflectionUtil就是爲了解決這類問題的輔助工具類,爲java.lang.reflect標準庫的工具類。它提供了便捷的訪問泛型對象類型(java.reflect.Type)的反射方法。java

本文假設你已經瞭解java反射知識,並能熟練的應用。若是還不瞭解java反射知識,那麼你能夠先移步到Oracel反射課程,這多是你開始學習反射的好起點.數組

ReflectionUtil中包含如下幾種功能:oracle

  1. 經過Type獲取對象class;
  2. 經過Type建立對象;
  3. 獲取泛型對象的泛型化參數;
  4. 檢查對象是否存在默認構造函數;
  5. 獲取指定類型中的特定field類型;
  6. 獲取指定類型中的特定method返回類型;
  7. 根據字符串標示獲取枚舉常量;
  8. ReflectionUtil下載地址.

經過Type獲取對象class

private static final String TYPE_NAME_PREFIX = "class ";

public static String getClassName(Type type) {
    if (type==null) {
        return "";
    }
    String className = type.toString();
    if (className.startsWith(TYPE_NAME_PREFIX)) {
        className = className.substring(TYPE_NAME_PREFIX.length());
    }
    return className;
}

public static Class<?> getClass(Type type) 
            throws ClassNotFoundException {
    String className = getClassName(type);
    if (className==null || className.isEmpty()) {
        return null;
    }
    return Class.forName(className);
}

方法ReflectionUtil#getClass(Type)實現了從java.lang.reflect.Type獲取java.lang.Class對象名稱。這裏利用了Type的toString方法獲取所在類型的class。如「class some.package.Foo」,截取後部分class名稱,在利用Class.forName(String)獲取class對象。函數

經過Type建立對象

public static Object newInstance(Type type) 
        throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    Class<?> clazz = getClass(type);
    if (clazz==null) {
        return null;
    }
    return clazz.newInstance();
}

方法ReflectionUtil#newInstance(Type type)實現根據Type構造對象實例。在這裏輸入的Type不能是抽象類、接口、數組類型、以及基礎類型、Void不然會發生InstantiationException異常。工具

獲取泛型對象的泛型化參數

首先假設咱們有以下兩個對象:學習

public abstract class Foo<T> {
    //content
}

public class FooChild extends Foo<Bar> {
    //content
}

怎麼獲取子類在Foo中傳入的泛型Class類型呢?this

比較經常使用的作法有如下兩種:code

強制FooChild傳入本身的class類型(這也是比較經常使用的作法):

public abstract class Foo<T> {
    private Class<T> tClass;    

    public Foo(Class<T> tClass) {
        this.tClass = tClass;
    }
    //content
}

public class FooChild extends Foo<Bar> {
    public FooChild() {
        super(FooChild.class);
    }
    //content
}

利用反射獲取:

public static Type[] getParameterizedTypes(Object object) {
    Type superclassType = object.getClass().getGenericSuperclass();
    if (!ParameterizedType.class.isAssignableFrom(superclassType.getClass())) {
        return null;
    }
    return ((ParameterizedType)superclassType).getActualTypeArguments();
}

方法ReflectionUtil#getParameterizedTypes(Object)利用反射獲取運行時泛型參數的類型,並數組的方式返回。本例中爲返回一個T類型的Type數組。對象

爲了Foo獲得T的類型咱們將會以下使用此方法:繼承

...
Type[] parameterizedTypes = ReflectionUtil.getParameterizedTypes(this);
Class<T> clazz = (Class<T>)ReflectionUtil.getClass(parameterizedTypes[0]);
...

注意:

在java.lang.reflect.ParameterizedType#getActualTypeArguments() documentation:的文檔中你能看見以下文字:

in some cases, the returned array can be empty. This can occur. if this type represents 
a non-parameterized type nested within a parameterized type.

當傳入的對象爲非泛型類型,則會返回空數組形式。

檢查對象是否存在默認構造函數

public static boolean hasDefaultConstructor(Class<?> clazz) throws SecurityException {
    Class<?>[] empty = {};
    try {
        clazz.getConstructor(empty);
    } catch (NoSuchMethodException e) {
        return false;
    }
    return true;
}

方法ReflectionUtil#hasDefaultConstructor利用java.lang.reflect.Constructor檢查是否存在默認的無參構造函數。

獲取指定類型中的特定field類型

public static Class<?> getFieldClass(Class<?> clazz, String name) {

if (clazz==null || name==null || name.isEmpty()) {
    return null;
}
name = name.toLowerCase();
Class<?> propertyClass = null;
for (Field field : clazz.getDeclaredFields()) {
    field.setAccessible(true);
    if (field.getName().equals(name)) {
        propertyClass = field.getType();
        break;
    }
}
return propertyClass;

}

在某些狀況下你但願利用已知的類型信息和特定的字段名字想獲取字段的類型,那麼ReflectionUtil#getFieldClass(Class<?>, String)能夠幫助你。ReflectionUtil#getFieldClass(Class<?>, String) 利用Class#getDeclaredFields()獲取字段並循環比較java.lang.reflect.Field#getName()字段名稱,返回字段所對應的類型對象。

獲取指定類型中的特定method返回類型

public static Class<?> getMethodReturnType(Class<?> clazz, String name) {
    if (clazz==null || name==null || name.isEmpty()) {
        return null;
    }   

    name = name.toLowerCase();
    Class<?> returnType = null;

    for (Method method : clazz.getDeclaredMethods()) {
        if (method.getName().equals(name)) {
            returnType = method.getReturnType();
            break;
        }
    }

    return returnType;
}

方法ReflectionUtil#getMethodReturnType(Class<?>, String)能夠幫助你根據對象類型和方法名稱獲取其所對應的方法返回類型。ReflectionUtil#getMethodReturnType(Class<?>, String)利用Class#getDeclaredMethods()並以java.lang.reflect.Method#getName()比對方法名稱,返回找到的方法的返回值類型(Method#getReturnType()).

根據字符串標示獲取枚舉常量

@SuppressWarnings({ "unchecked", "rawtypes" })
public static Object getEnumConstant(Class<?> clazz, String name) {
    if (clazz==null || name==null || name.isEmpty()) {
        return null;
    }
    return Enum.valueOf((Class<Enum>)clazz, name);
}

方法ReflectionUtil#getEnumConstant(Class<?>, String)爲利用制定的枚舉類型和枚舉名稱獲取其對象。這裏的名稱必須和存在的枚舉常量匹配。

ReflectionUtil下載地址

你能夠從這裏下載ReflectionUtil.java. 原英文版地址: http://qussay.com/2013/09/28/handling-java-generic-types-with-reflection/

相關文章
相關標籤/搜索