參考:我眼中的Java-Type體系(1)
我眼中的Java-Type體系(2)
Java 運行時如何獲取泛型參數的類型
Java類型Type 之 ParameterizedType,GenericArrayType,TypeVariabl,WildcardType
從實現的接口獲取泛型參數
定義一個泛型父類:
public interface SuperClass<P> {
String process(P p);
}
實現類1:
public class OneImpl implements SuperClass<House> {
@Override
public String process(House house) {
return null;
}
}
測試一下:
public static void main(String[] args) throws Exception {
SuperClass superClass = new OneImpl();
// 獲取運行時類型
System.out.println(superClass.getClass());
// 獲取實現的接口
Type[] types = superClass.getClass().getGenericInterfaces();
for (Type t : types) {
// ParameterizedType 的實現類:ParameterizedTypeImpl
System.out.println("ParameterizedTypeImpl: " + t.getClass().getName());
// 帶有泛型信息
System.out.println(t);
System.out.println(t instanceof ParameterizedType);
// 獲取聲明這個泛型的類或接口
System.out.println(((ParameterizedType) t).getRawType());
// 獲取泛型中的實際類型,可能存在多個泛型,比如 SuperClass<P, R>,所以會返回 Type[] 數組
Type[] paramGenericTypes = ((ParameterizedType) t).getActualTypeArguments();
for (Type actualType : paramGenericTypes) {
// 得到泛型的實際類型,這裏也就得到了 Class 類型
System.out.println("actualTypeName: " + actualType.getClass().getName());
System.out.println(actualType);
}
}
System.out.println("------------------------------");
// 獲取實現的接口
Class[] t = superClass.getClass().getInterfaces();
for (Class c : t) {
System.out.println(c);
}
}
輸出:
class com.jiaobucong.common.core.generic.OneImpl
ParameterizedTypeImpl: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
com.jiaobucong.common.core.generic.SuperClass<com.jiaobucong.common.core.generic.House>
true
interface com.jiaobucong.common.core.generic.SuperClass
actualTypeName: java.lang.Class
class com.jiaobucong.common.core.generic.House
------------------------------
interface com.jiaobucong.common.core.generic.SuperClass
實現類2,不帶泛型:
public class TwoImpl implements SuperClass {
@Override
public String process(Object o) {
return null;
}
}
來看測試:
public static void main(String[] args) throws Exception {
SuperClass superClass1 = new TwoImpl();
Type[] types1 = superClass1.getClass().getGenericInterfaces();
for (Type type : types1) {
System.out.println(type);
// 實現類沒有指定泛型參數,沒有對應的 ParameterizedTypeImpl 實現類
System.out.println(type instanceof ParameterizedType);
}
}
輸出:
interface com.jiaobucong.common.core.generic.SuperClass
false
通過 Method 方法級獲取泛型參數
public class GenericArrayTest {
public static void main(String[] args) throws Exception {
Method[] methods = OneGenericClass.class.getMethods();
for (Method method : methods) {
// 獲取每個方法的參數化類型
if (!"go".equals(method.getName())) {
continue;
}
Type[] parameters = method.getGenericParameterTypes();
// 不同的參數返回的Type類型是不一樣的
for (Type type : parameters) {
if (type instanceof Class) {
// 第一個參數
System.out.println("class: " + type);
} else if (type instanceof ParameterizedType) {
// 聲明這個泛型的類
Class<?> clazz = (Class<?>) ((ParameterizedType) type).getRawType();
System.out.println(type + ", ParameterizedType, "
+ "holderType: " + clazz
+ ", actual parameterized classes: "
+ Arrays.toString(getActualClass(type)));
} else if(type instanceof GenericArrayType) {
// 對於數組類型得到的是 GenericArrayType
Type arrayType = ((GenericArrayType) type).getGenericComponentType();
System.out.println(type + ", GenericArrayType, actual classes: "
+ Arrays.toString(getActualClass(arrayType)));
}
}
}
}
public static Class<?>[] getActualClass(Type type) {
if (type instanceof ParameterizedType) {
Type[] actualTypes = ((ParameterizedType) type).getActualTypeArguments();
Class<?>[] actualClasses = new Class[actualTypes.length];
for (int i = 0; i < actualTypes.length; i++) {
Type actualType = actualTypes[i];
if (actualType instanceof Class) {
actualClasses[i] = (Class<?>) actualType;
}
}
return actualClasses;
}
return null;
}
class OneGenericClass {
public void go(long userId, List<Long> orderIds, Map<String, Integer> map, List<Long>[] listArr) {
System.out.println(userId);
System.out.println(orderIds);
}
}
}
輸出:
class: long
java.util.List<java.lang.Long>, ParameterizedType, holderType: interface java.util.List, actual parameterized classes: [class java.lang.Long]
java.util.Map<java.lang.String, java.lang.Integer>, ParameterizedType, holderType: interface java.util.Map, actual parameterized classes: [class java.lang.String, class java.lang.Integer]
java.util.List<java.lang.Long>[], GenericArrayType, actual classes: [class java.lang.Long]
從 Field 獲取泛型參數
public class GenericTest1 {
private List<String>[] listArray;
private List<Long> list;
public static void main(String[] args) throws Exception {
test1();
System.out.println("-------------------test2");
test2();
}
public static void test1() throws Exception {
Field fieldListArray = GenericTest1.class.getDeclaredField("listArray");
Type type = fieldListArray.getGenericType();
// 這裏會報錯,得到的不是一個 ParameterizedType
// Type[] arrayType = ((ParameterizedType) type).getActualTypeArguments();
// 得到的是一個GenericArrayType,這個地方是一個泛型數組的類型,所以得到的是 GenericArrayType
// 得到的類型是去掉了最右邊的[],是 List<String>,得到的 arrayType 是 ParameterizedType
Type arrayType = ((GenericArrayType) type).getGenericComponentType();
System.out.println(arrayType);
System.out.println(arrayType.getClass().getName());
Type[] types = ((ParameterizedType) arrayType).getActualTypeArguments();
for (Type type1 : types) {
System.out.println(type1.getClass().getName());
// 這裏獲取到了 List<String>[] listArray <> 中的 String 類型
System.out.println(type1);
}
}
public static void test2() throws Exception {
Field fieldList = GenericTest1.class.getDeclaredField("list");
Type typeList = fieldList.getGenericType();
System.out.println(typeList.getClass().getName());
Type[] parameterTypes = ((ParameterizedType) typeList).getActualTypeArguments();
// 獲取 List<T> 中的 T 類型
for (Type type : parameterTypes) {
System.out.println(type.getClass().getName());
System.out.println(type);
}
// 定義這個 List 的類型
System.out.println(fieldList.getType());
}
}
輸出:
java.util.List<java.lang.String>
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
java.lang.Class
class java.lang.String
-------------------test2
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
java.lang.Class
class java.lang.Long
interface java.util.List
我們可以在類接口上、構造器上、方法上定義泛型類型,不同的泛型參數定義得到可能是 ParameterizedType、TypeVariable、Class、GenericArrayType,然後再通過得到的類型做不同的處理。