zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    正规替换( 图片 A )
    #1289 The 'InnoDB' feature is disabled; you need MySQL built with 'InnoDB' to hav
    appserv PHP环境配置简易套装
    DW格式化代设置
    ie6 清除li浮动
    wbox JS弹出层
    网页设计必备工具 firefox Web Developer插件 CSS工具组教程
    CSS块级元素和行内元素
    dreamweaver代码 格式化
    iphone下Three20库(From Facebook)的设置使用方法
  • 原文地址:https://www.cnblogs.com/zhangmingda/p/14781377.html
Copyright © 2011-2022 走看看