當(dāng)我們聲明了一個(gè)泛型的接口或類,或需要一個(gè)子類繼承至這個(gè)泛型類,而我們又希望利用反射獲取這些泛型參數(shù)信息。這就是本文將要介紹的ReflectionUtil就是為了解決這類問題的輔助工具類,為java.lang.reflect標(biāo)準(zhǔn)庫的工具類。它提供了便捷的訪問泛型對象類型(java.reflect.Type)的反射方法。
本文假設(shè)你已經(jīng)了解java反射知識(shí),并能熟練的應(yīng)用。如果還不了解java反射知識(shí),那么你可以先移步到Oracel反射課程,這可能是你開始學(xué)習(xí)反射的好起點(diǎn).
ReflectionUtil中包含以下幾種功能:
通過Type獲取對象class;
通過Type創(chuàng)建對象;
獲取泛型對象的泛型化參數(shù);
檢查對象是否存在默認(rèn)構(gòu)造函數(shù);
獲取指定類型中的特定field類型;
獲取指定類型中的特定method返回類型;
根據(jù)字符串標(biāo)示獲取枚舉常量;
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)實(shí)現(xiàn)了從java.lang.reflect.Type獲取java.lang.Class對象名稱。這里利用了Type的toString方法獲取所在類型的class。如“class some.package.Foo”,截取后部分class名稱,在利用Class.forName(String)獲取class對象。
通過Type創(chuàng)建對象
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)實(shí)現(xiàn)根據(jù)Type構(gòu)造對象實(shí)例。在這里輸入的Type不能是抽象類、接口、數(shù)組類型、以及基礎(chǔ)類型、Void否則會(huì)發(fā)生InstantiationException異常。
獲取泛型對象的泛型化參數(shù)
首先假設(shè)我們有如下兩個(gè)對象:
public abstract class Foo<T> {
//content
}
public class FooChild extends Foo<Bar> {
//content
}
怎么獲取子類在Foo中傳入的泛型Class類型呢?
比較常用的做法有以下兩種:
強(qiáng)制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)利用反射獲取運(yùn)行時(shí)泛型參數(shù)的類型,并數(shù)組的方式返回。本例中為返回一個(gè)T類型的Type數(shù)組。
為了Foo得到T的類型我們將會(huì)如下使用此方法:
...
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.
當(dāng)傳入的對象為非泛型類型,則會(huì)返回空數(shù)組形式。
檢查對象是否存在默認(rèn)構(gòu)造函數(shù)
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檢查是否存在默認(rèn)的無參構(gòu)造函數(shù)。
獲取指定類型中的特定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()獲取字段并循環(huán)比較java.lang.reflect.Field#getName()字段名稱,返回字段所對應(yīng)的類型對象。
獲取指定類型中的特定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)可以幫助你根據(jù)對象類型和方法名稱獲取其所對應(yīng)的方法返回類型。ReflectionUtil#getMethodReturnType(Class<?>, String)利用Class#getDeclaredMethods()并以java.lang.reflect.Method#getName()比對方法名稱,返回找到的方法的返回值類型(Method#getReturnType()).
根據(jù)字符串標(biāo)示獲取枚舉常量
@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)為利用制定的枚舉類型和枚舉名稱獲取其對象。這里的名稱必須和存在的枚舉常量匹配。
更多信息請查看IT技術(shù)專欄