如何在執行時(Runtime)獲得泛型的真正型別
前言
由於Java 的型別擦除機制,在編譯時泛型都被轉為了Object,例如List<String>
經過編譯之後將變為型別 List。可以通過以下的方式再執行時獲得泛型的真正型別
泛型如何獲得具體型別
List 例子如下
來自:https://stackoverflow.com/questions/1942644/get-generic-type-of-java-util-list
package test; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.List; public class Test { List<String> stringList = new ArrayList<String>(); List<Integer> integerList = new ArrayList<Integer>(); public static void main(String... args) throws Exception { Field stringListField = Test.class.getDeclaredField("stringList"); ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType(); Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0]; System.out.println(stringListClass); // class java.lang.String. Field integerListField = Test.class.getDeclaredField("integerList"); ParameterizedType integerListType = (ParameterizedType) integerListField.getGenericType(); Class<?> integerListClass = (Class<?>) integerListType.getActualTypeArguments()[0]; System.out.println(integerListClass); // class java.lang.Integer. } }
Map 的例子如下
來自:https://stackoverflow.com/questions/3687766/how-to-get-value-type-of-a-map-in-java
import java.lang.reflect.*; import java.util.*; public class Generic { private Map<String, Number> map = new HashMap<String, Number>(); public static void main(String[] args) { try { ParameterizedType pt = (ParameterizedType)Generic.class.getDeclaredField("map").getGenericType(); for(Type type : pt.getActualTypeArguments()) { System.out.println(type.toString()); } } catch(NoSuchFieldException e) { e.printStackTrace(); } } }
實際二者都利用的反射,都是基於 java.lang.reflect.ParameterizedType
jackson 中如何反序列化泛型
jackson 中將JSON 轉為Map 的可以通過如下程式碼實現,方式一:
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"mkyong\", \"age\":29}";
Map map = mapper.readValue(json, Map.class);
Object name = map.get("name")
上述只是指定了是 Map 型別,但是沒有指定Map裡邊存放的資料是什麼型別,所以得到結果之後還需要對 Object name
可以使用方式二,告知實際 Map
中存放的物件,從而得到正確的型別,程式碼如下所示:
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"mkyong\", \"age\":29}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, String>>(){});
TypeReference
實際上就是告訴了 ObjectMapper
反序列化時要轉換的真正型別是什麼。
TypeReference 原始碼
package com.fasterxml.jackson.core.type;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public abstract class TypeReference<T> implements Comparable<TypeReference<T>> {
protected final Type _type;
protected TypeReference() {
Type superClass = this.getClass().getGenericSuperclass();
if (superClass instanceof Class) {
throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
} else {
this._type = ((ParameterizedType)superClass).getActualTypeArguments()[0];
}
}
public Type getType() {
return this._type;
}
public int compareTo(TypeReference<T> o) {
return 0;
}
}
有一個 protected
的構造器,所以在使用的時候預設就會執行該構造器,上述方案二將會走到分支程式碼 this._type = ((ParameterizedType)superClass).getActualTypeArguments()[0];
,從而 getType
能夠得到正確的型別。實際上也是根據 ParameterizedType
獲得真正的型別。
通過 TypeReference 獲得真正型別
程式碼類似如下,最後得到的 tmpType1
是 Class
型別,就能夠基於它其他的操作了。
TypeReference<Map<String, Test>> typeReference = new TypeReference<Map<String, Test>>(){};
ParameterizedType type = (ParameterizedType)typeReference.getType();
for (Type tmpType : type.getActualTypeArguments()) {
Class<?> tmpType1 = (Class<?>) tmpType;
System.out.println(tmpType1);
}
來源:https://www.cnblogs.com/xiaoheike/p/9867060.html