利用Java反射处理private变量#yyds干货盘点#

Posted FunTester

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用Java反射处理private变量#yyds干货盘点#相关的知识,希望对你有一定的参考价值。

在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 !

以上是关于利用Java反射处理private变量#yyds干货盘点#的主要内容,如果未能解决你的问题,请参考以下文章

Java-利用反射访问类的私有(private)属性及方法&private的意义

Java如何访问private变量

既然Java反射可以访问和修改私有成员变量,那封装成private还有意义么?

JAVA反射机制

Java反射-修改private final成员变量值,你知道多少?

利用反射生成 MyBatisPlus中QueryWrapper动态条件 #yyds干货盘点#