本文将介绍如何利用java反射机制修改属性值,废话不多说,直接上代码
1、新建一个实体类,添加属性test以及获取属性值的方法getTest()
public class ReflectTest {
//测试修改属性
String test = "修改前的值";
public String getTest(){
return test;
}
}
2、新建一个测试类,利用反射机制获取类对象、方法、属性,方法对象调用invoke()执行方法
class Test{
public static void main(String[] args) throws Exception {
//获取ReflectTest类的class对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//获取实例对象
ReflectTest reflectTest = reflectTestClass.newInstance();
//获取属性对象
Field testField = reflectTestClass.getDeclaredField("test");
//获取方法对象
Method getTestMethod = reflectTestClass.getDeclaredMethod("getTest", null);
//执行方法
Object invoke = getTestMethod.invoke(reflectTest);
System.out.println(invoke);
}
}
修改前得到的打印结果如下
3、以上为默认修饰符属性未修改的情况,现在我们通过testField.set(reflectTest,“修改后的值”)修改属性值;修改默认属性代码如下:
//获取ReflectTest类的class对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//获取实例对象
ReflectTest reflectTest = reflectTestClass.newInstance();
//获取属性对象
Field testField = reflectTestClass.getDeclaredField("test");
//修改属性值
testField.set(reflectTest,"修改后的值");
//获取方法对象
Method getTestMethod = reflectTestClass.getDeclaredMethod("getTest", null);
//执行方法
Object invoke = getTestMethod.invoke(reflectTest);
System.out.println(invoke);
修改后打印结果如下:
4、默认属性可以修改,那么其他属型呢?我们依次试试public、protected,修改后打印结果均为“修改后的值”。修改private修饰的属性值时却抛出异常IllegalAccessException。原来,在利用反射机制修改私有属性的值前,需要执行setAccessible(true),这样就能绕过private的限制啦,改动代码和结果如下:
//获取属性对象
Field testField = reflectTestClass.getDeclaredField(“test”);
testField.setAccessible(true);
//修改属性值
testField.set(reflectTest,“修改后的值”);
打印结果:
5、默认、public、protected、private都修改成功了,那么如果都换成静态修饰的呢?小编一一测试之后依然是能够实现的。那么final修饰的属性是否能够被修改呢?
这里首先将属性改为final修饰:
private final String test = “修改前的值”;
修改属性的代码不变:
//获取属性对象
Field testField = reflectTestClass.getDeclaredField("test");
testField.setAccessible(true);
//修改属性值
testField.set(reflectTest,"修改后的值");
//获取方法对象
Method getTestMethod = reflectTestClass.getDeclaredMethod("getTest", null);
//执行方法
Object invoke = getTestMethod.invoke(reflectTest);
System.out.println(invoke);
得到的结果如下,仍然是修改前的值:
这里可以看见我们打印类的属性值并没有改变,当前反射获取到的属性值却发生了改变,代码和结果如下:
//获取属性对象
Field testField = reflectTestClass.getDeclaredField("test");
testField.setAccessible(true);
//修改属性值
testField.set(reflectTest,"修改后的值");
System.out.println(testField.get(reflectTest));
执行以上代码结果如下:
6、为了修改final修饰的类属性的值,我们要对 Java 反射包中的类进行自我反射。Field 对象有个一个属性叫做 modifiers, 它表示的是属性是否是 public, private, static, final 等修饰的组合。这里把这个 modifiers 也反射出来,进而把 nameField 的 final 约束去掉。代码如下:
//获取ReflectTest类的class对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//获取实例对象
ReflectTest reflectTest = reflectTestClass.newInstance();
//获取属性对象
Field testField = reflectTestClass.getDeclaredField("test");
//获取modifiers属性,modifiers属性也是私有的
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
//改掉testField属性的modifiers 值 按位取反再按位与 操作把 final 从修饰集中剔除掉,
// 其他特性如 private, static 保持不变
modifiers.setInt(testField,testField.getModifiers() & ~Modifier.FINAL);
testField.setAccessible(true);
//修改属性值
testField.set(reflectTest,"修改后的值");
//获取方法对象
Method getTestMethod = reflectTestClass.getDeclaredMethod("getTest", null);
//执行方法
Object invoke = getTestMethod.invoke(reflectTest);
System.out.println(invoke);
此时运行程序没有报错,但打印出来的还是修改前的值,原因是编译期间final类型的数据自动被优化,“修改前的值”是直接在常量区内取的值,我们将其换成基本数据类型也是一样,均是取得常量区的值。而使用new String(“修改前的值”)进行初始化编译期间不会被优化:
private final String test = new String(“修改前的值”);