java 編程基礎 反射方式獲取泛型的類型Fileld.getGenericType() 或Method.getGenericParameterTypes(); (ParameterizedType) ;getActualTypeArguments()


引言

自從JDK5以后,Java Class類增加了泛型功能,從而允許使用泛型來限制Class類,例如,String.class的類型實際上是 Class 如果 Class 對應的類暫時未知,則使 Class<?>。通過在反射中使用泛型,可以避免使用反射生成的對象需要強制類型轉換。
泛型作用對比:
如下示例沒有使用泛型時,編譯不報錯,運行時報錯強制轉換異常
public class HasNoFanxin {
    public static Object newInstance(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Class clz = Class.forName(className);
        return clz.newInstance();
    }
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        String str = (String) newInstance("java.lang.Date");
        System.out.println(str);
    }
}

如下使用泛型,輸入有誤的話編譯時就會報異常,提前提示錯誤(編譯時就自動推斷了泛型的真實類型)

public class HasFanxin {
    public static <T> T newInstance(Class<T> clz) throws InstantiationException, IllegalAccessException {
        return clz.newInstance();
    }

    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Date str = newInstance(Date.class); // 這里傳入什么類型,傳出就必須是什么類型,如果寫成了String str = ... 就會編譯報錯
    }
}

通過反射獲取變量、方法形參的泛型類型

以獲取類變量泛型為例

前提:
通過反射獲取類對應的 成員變量Field
獲取步驟:
1. 獲得成員變量的類型
  • Type gType = f.getGenericType();
2. 判斷類型是否為帶泛型的類型
  • gtype instanceof ParameterizedType
3. 將判斷為待泛型的Type對象強制轉換為ParameterizedType對象,(ParameterizedType代表被參數化的類型:也就是增加了泛型限制的類型)
  • ParameterizedType ptype = (ParameterizedType) type
4.通過強制轉換后的ParameterizedType帶泛型對象獲取泛型的類型

getRawType() 返回沒有泛型信息的原始類型。

getActualTypeArguments(): 返回泛型參數的類型Type 數組。

  • Type[] types = ptype.getActualTypeArguments();

獲取方法參數的泛型,可以通過反射方法的參數本身Parameter反射對象,再通過反射對象的getParameterizedType()方法獲取本參數的類型的Type對象,進行如上第 2.步驟及以后

或者

通過反射的方法Method對象,通過Method對象getGenericParameterTypes()方法,直接獲取所有形參的類型組成的Type數組,再循環經過第 2.步驟及以后

 

package com.zmd.fanxingfanshe;

import java.lang.reflect.*;
import java.util.List;
import java.util.Map;

/**
 * @ClassName FanxingTest
 * @projectName: object1
 * @author: Zhangmingda
 * @description: XXX
 * date: 2021/5/17.
 */
public class FanxingTest {
    //帶泛型的屬性(類變量或實例變量)
    private Map<String, Integer> data;
    private String string;
    //定義帶泛型的方法
    private static void fanxingMethod(Map<String, Integer> users, String list){

    }
    //測試獲取泛型
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
        //獲取類
        Class<FanxingTest> cls = FanxingTest.class;
        //獲取類變量
        Field dataField = cls.getDeclaredField("data");
        System.out.println("=========獲取類變量泛型類型===============");

        //輸出data的類型interface java.util.Map
        System.out.println("data 的類型:" + dataField.getType());

        //獲取對應的帶泛型類型
        Type gtype = dataField.getGenericType();
        System.out.println("參數類型:" + gtype); //java.util.Map<java.lang.String, java.lang.Integer>
        if (gtype instanceof ParameterizedType){
            //將Type對象強制類型轉換為ParameterizedType對象
            ParameterizedType ptype = (ParameterizedType) gtype;
            System.out.println(ptype);
            System.out.println(gtype + "的原始類型:" + ptype.getRawType());
            //獲取對應的泛型的類型
            Type[] tTypes = ptype.getActualTypeArguments();
            for (Type tType : tTypes){
                System.out.println(tType);
            }
        }


        /**
         * 獲取方法形參的泛型
         */
        System.out.println("=========通過反射獲取方法,再通過方法getGenericParameterTypes獲取形參泛型類型:===============");
        //輸入方法名和參數的類列表,獲取具體方法的反射
        Method fxMethod = cls.getDeclaredMethod("fanxingMethod", Map.class, String.class);
        //設置private類型方法可訪問
        fxMethod.setAccessible(true);
        //獲取所有參數類型列表
        Type[] parameterTypes = fxMethod.getGenericParameterTypes();
        for (Type type: parameterTypes){
            //當前參數類型
            System.out.println("參數類型" + type);
            if (type instanceof ParameterizedType){
                ParameterizedType ptype = (ParameterizedType) type;
                //原始類型
                System.out.println("參數原始類型:" + ptype.getRawType());
                //獲取對應泛型的類型
                Type[] types = ptype.getActualTypeArguments();
                for (Type tType: types){
                    System.out.println(tType);
                }
            }
        }

        //通過反射參數自身反射泛型
        System.out.println("=========通過反射獲取方法,再通過方法獲取參數反射,再通過參數.getParameterizedType()獲取形參泛型類型:===============");
        Parameter[] parameters = fxMethod.getParameters();
        for (Parameter parameter : parameters){
            System.out.println("獲取到參數:" + parameter.getName());
            Type type = parameter.getParameterizedType();
            System.out.println(parameter.getName() + "參數的類型:" + type);
            if (type instanceof ParameterizedType){
                ParameterizedType parameterizedType = (ParameterizedType) type;
                System.out.println(parameter.getName() + "參數的原始類型:"+ parameterizedType.getRawType());
                Type[] types = parameterizedType.getActualTypeArguments();
                for (Type type1 : types){
                    System.out.println(type1);
                }
            }
        }
    }
}

輸出

=========獲取類變量泛型類型===============
data 的類型:interface java.util.Map
參數類型:java.util.Map<java.lang.String, java.lang.Integer>
java.util.Map<java.lang.String, java.lang.Integer>
java.util.Map<java.lang.String, java.lang.Integer>的原始類型:interface java.util.Map
class java.lang.String
class java.lang.Integer
=========通過反射獲取方法,再通過方法getGenericParameterTypes獲取形參泛型類型:===============
參數類型java.util.Map<java.lang.String, java.lang.Integer>
參數原始類型:interface java.util.Map
class java.lang.String
class java.lang.Integer
參數類型class java.lang.String
=========通過反射獲取方法,再通過方法獲取參數反射,再通過參數.getParameterizedType()獲取形參泛型類型:===============
獲取到參數:arg0
arg0參數的類型:java.util.Map<java.lang.String, java.lang.Integer>
arg0參數的原始類型:interface java.util.Map
class java.lang.String
class java.lang.Integer
獲取到參數:arg1
arg1參數的類型:class java.lang.String

Process finished with exit code 0

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM