前言
由於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); }
歡迎轉載,但請註明本文鏈接,謝謝你。