Java如何獲取泛型類型

參考:我眼中的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,然後再通過得到的類型做不同的處理。

發佈了139 篇原創文章 · 獲贊 181 · 訪問量 74萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章