当反射遇上泛型

通过定义类(匿名内部类)的方式,在类信息中保留泛型信息,从而在运行时获得这些泛型信息。

一个简单的实体类:

public class Bean {
        private int i;
        public List<String> list;

        public Bean() {

        }

        public void setI(int i) {
            this.i = i;
        }

        public int getI() {
            return i;
        }

        private String getCS() {
            return "获取私有化无参方法";
        }

        private String getCS2(String str) {
            return "获取私有化无参方法" + str;
        }

        private String[] arrayShow(String[] arr) {
            return arr;
        }
    }

通过反射操作类中的属性和方法

    /**
     * getDeclaredXX :会获得Class中的所有内容,
     * getXX: 获得当前类以及父类的内容,但是不包括非public
     */
    private void initReflect() {
        Class<Bean> beanClass = Bean.class;
        Bean bean = new Bean();
        //获得类以及父类中所有声明为public的属性
        System.out.println("所有public属性:");
        for (Field field : beanClass.getFields()) {
            Log.d(TAG, "initReflect: " + field.getName());
        }
        //获得类(不包括父类)中所有的属性
        System.out.println("所有属性:");
        for (Field field : beanClass.getDeclaredFields()) {
            Log.d(TAG, "initReflect: " + field.getName());
            //对于非public的Field/Method进行操作,需要先进行:setAccessible(true)
            if ("i".equals(field.getName())) {
                field.setAccessible(true);
                try {
                    field.setInt(bean, 3);
                    Log.d(TAG, "initReflect: 改变私有化属性值i=" + field.getInt(bean));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        //获得类以及父类中所有声明为public的函数
        System.out.println("所有public函数:");
        for (Method method : beanClass.getMethods()) {
            Log.d(TAG, "initReflect: " + method.getName());
        }

        //获得类(不包括父类)中所有的函数
        System.out.println("所有函数:");
        for (Method method : beanClass.getDeclaredMethods()) {
            Log.d(TAG, "initReflect: " + method.getName());
            if ("getCS".equals(method.getName())) {
                method.setAccessible(true);//public修饰的方法不需要此操作
                try {
//                    执行无参私有方法
                    Object object = method.invoke(bean, null);
                    Log.d(TAG, "initReflect无参私有方法: " + object);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }

            }
//                    执行有参私有方法
            if ("getCS2".equals(method.getName())) {
                method.setAccessible(true);
                try {
                    Object object = method.invoke(bean, "参数私有方法传入");
                    Log.d(TAG, "initReflect:******** " + object);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }

            // 执行数组类型参数的私有方法
            if ("arrayShow".equals(method.getName())) {
                method.setAccessible(true);
                try {

                    //数组类型的参数必须包含在new Object[]{}中,否则会报IllegalArgumentException
                    String[] strs = new String[]{"若森", "画江湖", "秦时明月", "天行九歌"};
                    String[] strings = (String[]) method.invoke(bean, new Object[]{strs});
                    for (String str : strings) {
                        System.out.println("arrayShow的数组元素:" + str);
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }

        }

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }

效果图

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

类中List集合的泛型类型

// 类中的属性对应反射中的Field,而函数则为Method。但是获取构造方法,则需要通过Constructor:
//         Java 泛型在运行的时候是会进行类型擦除,泛型信息只存在于代码编译阶段。
// 即对于List<String>和List<Integer>在运行阶段都是List.class,泛型信息被擦除了。
//        引入泛型擦除的原因是避免因为引入泛型而导致运行时创建不必要的类。
// Java 的泛型擦除是有范围的,除了结构化信息外的所有东西会擦除,
// 与类及其字段和方法的类型参数相关的元数据都会被保留下来,可以通过反射获取到。
        Constructor<?>[] constructors = beanClass.getConstructors();
        Log.d(TAG, "constructors.length: " + constructors.length);
//        对于以下List<String>和List<Integer>在运行阶段都是List.class,泛型信息被擦除了。
        List<String> l1 = new ArrayList<String>();
        List<Integer> l2 = new ArrayList<Integer>();
        assert (l1.getClass() == l2.getClass()); //结果为真
//        所以这时候没法通过Class<?> type = Field.getType获得需要的Class<String>。
//         但是Java为我们提供了 Type 接口,使用它我们可以得到这些信息。
//        Type是一个接口,它的实现类有Class,子接口有 ParameterizedType, WildcardType等。
//        如果希望获得某个类中List集合的泛型类型,则可以:
        //指定获得Bean中list属性
        Field list = null;
        try {
            list = Bean.class.getField("list");
            // 属性对应的Class如果是List或其子类
            if (List.class.isAssignableFrom(list.getType())) {
                //获得 Type
                Type genericType = list.getGenericType();
                //ParameterizedType 如果超类实现了参数化类型接口
                if (genericType instanceof ParameterizedType) {
                    //获得泛型类型
                    Type type = ((ParameterizedType) genericType).getActualTypeArguments()[0];
                     //WildcardType  如果使用了通配符
                    //  在泛型中可以通过通配符来声明一个泛型类型,即使用?。同时可以指明?的上下边界。带上边界的通配符: List<? extends Number> list;带下边界的通配符:List<? super Integer> list。
                    //  getUpperBounds:获得上边界。
                    //  对于List<? extends Number> list上边界为Number,而List<? super Integer> list上边界则为:Object。
                    if (type instanceof WildcardType) {
                        WildcardType wildcardType = (WildcardType) type;
                        Type[] upperBounds = wildcardType.getUpperBounds();
                        if (upperBounds.length == 1) {
                            Type actualTypeArgument = upperBounds[0];
                            System.out.println("获得泛型上边界类型:" + actualTypeArgument);
                        }
                    } else {
                        System.out.println("获得泛型类型:" + type);
                    }
                }
            }

泛型类

  public class TypeReference<T> {
        protected TypeReference() {
            //获取当前对象的直接超类的 Type
             Type superClass = getClass().getGenericSuperclass();
            Type oriType = ((ParameterizedType) superClass).getActualTypeArguments()[0];
            System.out.println("泛型类oriType:"+oriType);
        }
    }

。。。。。
 new TypeReference<Object>(){};//当new这个类的时候,实际上是创建了一个匿名内部类。TypeReference的子类,泛型参数限定为Object。

泛型运行效果

这里写图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值