使用Java反射修改private static final字段抛出IllegalAccessException问题
问题原因
- 修饰符修改逻辑代码错误
你现有代码中尝试获取修饰符字段的逻辑有误,你调用Table.getDeclaredField(GeneratedValueFields.get(i).getName())获取到的依旧是自定义类的id字段,而非java.lang.reflect.Field类中存储字段修饰符的modifiers属性。你试图给Long类型的id字段设置int类型的修饰符值,自然会抛出类型不匹配的IllegalAccessException。 - static final字段的JVM特殊限制
JVM会在类加载阶段对static final修饰的常量做内联优化,直接把常量值嵌入到所有引用该字段的代码位置,同时反射对static final字段的修改权限限制远高于实例final字段。就算正确移除final修饰符,部分JDK版本(尤其是JDK9+的模块化机制)仍然会拦截static final字段的写入操作,这也是你删除修饰符修改代码后,即使类型匹配仍然抛出访问异常的原因。 - 实例final字段无全局内联限制
实例final字段不会在类加载阶段做全局内联优化,仅需移除final修饰符后就可以给对应实例的该字段赋值,不需要处理类层面的限制,因此可以正常运行。
解决办法
- 首先修正修饰符修改代码,正确从
Field类获取修饰符字段:
for (Field field : Table.getDeclaredFields()){ System.out.println(Table.getSimpleName()); //prints "Item" field.setAccessible(true); if (field.getName().equals(GeneratedValueFields.get(i).getName())) { System.out.println(field.getName()); //prints "id" // 修正:从Field类获取modifiers字段,而非自定义的Table类 Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); // 确保data是Long类型,避免类型不匹配 Long data = Long.valueOf(9); field.set(null,data); } }
- 适配高版本JDK限制:如果你使用JDK9及以上版本,需要添加JVM启动参数解除模块化反射限制:
--add-opens java.base/java.lang.reflect=ALL-UNNAMED - 优先避免修改static final字段:该操作本身稳定性极差,即使修改成功,之前已经内联了该常量的代码依旧会使用旧值,只有通过反射读取才能拿到新值,极易出现逻辑不一致。如果业务允许,优先改为实例final字段,或者去掉static修饰符。
- 确保赋值类型匹配:如果字段类型为
Long,赋值时必须传入Long类型的值,不能直接传入int类型的字面量,避免自动装箱为Integer导致类型不匹配异常。
内容的提问来源于stack exchange,提问作者Ilias Tzortzinis
相关产品推荐
相关产品推荐

