• 让天下没有难学的技术
    多数学员都来自推荐,这就是口碑的力量

利用 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

 

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注