1. 程式人生 > >如何在執行時(Runtime)獲得泛型的真正型別

如何在執行時(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

 

鄭州男科醫院哪裡好

鄭州婦科醫院

鄭州做人流價格是多少錢

鄭州婦科醫院哪家好