• 利用Java反射处理private变量


    在Java基础中,private是一个访问权限最严格的修饰符。但是在我们工作当中,使用第三方jar包的时候甚至使用JDK里面的工具类的时候,经常会遇到一些private修饰变量,我们想访问甚至修改这个变量的时候就显得比较麻烦。

    这个时候我们需要通过Java反射方案来实现我们访问和修改private修饰的变量。

    核心API

    java.lang.reflect.Field类中有一个java.lang.reflect.AccessibleObject#setAccessible(boolean)方法可以设置反射访问变量的时候跳过权限检查。

    这个API不仅可以访问对象变量,也可以访问静态变量。

    封装类

    这个是Groovy写的,对JDK的反射相关API进行了封装,其中有些异常并没有处理。

    package com.funtester.utils
    
    import com.funtester.base.exception.FailException
    
    import java.lang.reflect.Field
    import java.lang.reflect.InvocationTargetException
    import java.lang.reflect.Method
    
    /**
     * 私有变量访问工具类,可用于final修饰的变量
     */
    class PriUtil {
    
        /***
         * 获取私有成员变量的值
         *
         */
        static <F> F get(Object instance, String name, Class<F> f) {
            try {
                Field field = instance.getClass().getDeclaredField(name);
                field.setAccessible(true); // 参数值为true,禁止访问控制检查
    
                return (F) field.get(instance);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                FailException.fail("获取${instance.toString()}私有变量$name 失败 ${e.getMessage()}");
            }
        }
    
        /***
         * 设置私有成员变量的值
         *
         */
        static void set(Object instance, String fileName, Object value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
    
            Field field = instance.getClass().getDeclaredField(fileName);
            field.setAccessible(true);
            field.set(instance, value);
        }
    
        /***
         * 访问私有方法
         *
         */
        static <F> F call(Object instance, String name, Class<F> r, Class[] parameterTypes, Object[] params) {
            Method method = instance.getClass().getDeclaredMethod(name, parameterTypes);
            method.setAccessible(true);
            return (F) method.invoke(instance, params);
        }
    
        /**
         * 获取static变量
         * @param c
         * @param name
         * @param f
         * @return
         */
        static <F> F get(Class c, String name, Class<F> f) {
            Field[] fields = c.getDeclaredFields();
            try {
                for (Field field : fields) {
                    field.setAccessible(true);
                    if (field.getType() == f && field.getName().equals(name))
                        return (F) field.get(c);
                }
            } catch (Exception e) {
                FailException.fail("获取${c.name}私有变量$name 失败 ${e.getMessage()}");
            }
        }
    
        /**
         * 设置static变量
         * @param c
         * @param name
         * @param f
         */
        static void set(Class c, String name, Object f) {
            Field[] fields = c.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                if (field.getName().equals(name))
                    field.set(c, f)
            }
        }
    
        /**
         * 调用私有static方法
         * @param c
         * @param name
         * @param r
         * @param parameterTypes
         * @param params
         * @return
         */
        static <F> Object call(Class c, String name, Class<F> r, Class[] parameterTypes, Object[] params) {
            try {
                Method method = c.getMethod(name, parameterTypes);
                method.setAccessible(true);
                return (F) method.invoke(null, params);
            } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                FailException.fail("执行${c.name}私有方法$name 失败,参数 ${e.getMessage()}")
            }
        }
    
    }
    
    

    测试类

    这里我简单写了一个测试类,一个成员变量,一个类变量。

    /**
     * 反射访问private测试类
     */
    public class PriBase {
    
        private String name = "FunTester";
    
        private static String cname = "CFunTester";
    
    }
    
    

    测试脚本

    首先我测试一下非静态变量,测试脚本如下:

    import com.funtester.frame.SourceCode
    import com.funtester.utils.PriUtil
    
    class PriTest extends SourceCode{
    
        public static void main(String[] args) {
            PriBase base = new PriBase()
            PriUtil.set(base,"name","修改后name")
            String get = PriUtil.get(base, "name", String.class)
            output(get)
            PriBase base1 = new PriBase()
            String get1 = PriUtil.get(base1, "name", String.class)
            output(get1)
        }
    }
    
    

    控制台输出:

    INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
    INFO-> main 
      ###### #     #  #    # ####### ######  #####  ####### ######  #####
      #      #     #  ##   #    #    #       #         #    #       #    #
      ####   #     #  # #  #    #    ####    #####     #    ####    #####
      #      #     #  #  # #    #    #            #    #    #       #   #
      #       #####   #    #    #    ######  #####     #    ######  #    #
    
    INFO-> main 修改后name
    INFO-> main FunTester
    
    Process finished with exit code 0
    
    

    其次我们测试一下静态变量,测试脚本如下:

    import com.funtester.frame.SourceCode
    import com.funtester.utils.PriUtil
    
    class PriTest extends SourceCode{
    
        public static void main(String[] args) {
            PriUtil.set(PriBase.class,"cname","修改后name")
            String get = PriUtil.get(PriBase.class, "cname", String.class)
            output(get)
        }
    }
    
    

    控制台输出:

    INFO-> main 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
    INFO-> main 
      ###### #     #  #    # ####### ######  #####  ####### ######  #####
      #      #     #  ##   #    #    #       #         #    #       #    #
      ####   #     #  # #  #    #    ####    #####     #    ####    #####
      #      #     #  #  # #    #    #            #    #    #       #   #
      #       #####   #    #    #    ######  #####     #    ######  #    #
    
    INFO-> main 修改后name
    
    Process finished with exit code 0
    
    

    完美实现我们的需求,以后再也不用管什么访问权限了,哈哈哈~~~

    欢迎关注FunTester,Have Fun ~ Tester !

  • 相关阅读:
    DataTable:数据库到程序的桥梁
    《Javascript高级程序设计》阅读记录(三):第五章 上
    《Javascript高级程序设计》阅读记录(二):第四章
    javascript获取窗口位置、绝对位置、事件位置等
    《Javascript高级程序设计》阅读记录(一):第二、三章
    调试用随笔
    C#值类型和引用类型
    vue使用vue-awesome-swiper及一些问题
    npm与yarn命令对比
    npm与nrm
  • 原文地址:https://www.cnblogs.com/FunTester/p/15692670.html
Copyright © 2020-2023  润新知