问题
反射到底能否修改被private static final修饰的属性?按常规反射获取属性,然后赋值,会发生什么?
代码
反射要修改的属性是Test2.NUMBER
public class Test2 {
private static final Integer NUMBER = 1;
public static Integer getNumber() {
return NUMBER;
}
测试方法
@Test
public void test() throws Exception {
Field number = Test2.class.getDeclaredField("NUMBER");
Test2 o = Test2.class.newInstance();
number.setAccessible(true);
number.set(o, 3);
System.out.println(Test2.getNumber());
}
我们期望输出的是3,而结果会抛出如下异常:
网上查了很多例子,关于String的这里不再追述,关于int或Integer的,也基本都是说不能用反射赋值。
但是真的就不行了吗,是不能用反射,还是不能这样用反射呢?
结果
正好我最近发现hugegraph新版代码中有这个问题,于是提了issue,维护人员刚刚回复他们会去核实代码中是否存在此问题,并且告诉我如果要使用源码,可以先参考这个链接解决上述问题
stackoverflow解决此问题的地址
方法如下,参数1,要赋值的属性,参数2,新值
private static void setFinalStatic(Field field, Object newValue) throws NoSuchFieldException, IllegalAccessException {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
原demo中用的是Boolean,将false成功改成了true,我这里还是使用上述的Integer,测试方法如下
@Test
public void test() throws Exception {
Field number = Test2.class.getDeclaredField("NUMBER");
setFinalStatic(number, 3);
System.out.println(Test2.getNumber());
}
神奇的事情发生了,Test2.NUMBER原值是1,这里输出了3
于是我尝试将Test2中的NUMBER修改为int,看看如果不是包装类型,还能否修改,结果如下:
看来这种方法对包装类型的private static final可以进行修改了,但对于基本类型,虽然不会抛出之前的异常了,但仍然无法成功赋值。
对于这种方法的原理还没有理解,还是不太建议在生产环境中使用这样的代码。当然了,生产环境自己写的代码,大概率也不会想去写成private static final再去反射修改。如果是必须要对引入的第三方jar中的属性做修改,或许可以尝试尝试。