父类反射方法被子类调用时更新子类私有字段触发权限异常问题
问题解答
这是完全符合Java语言规范的预期行为,核心逻辑与Java访问控制机制、反射调用的上下文判定规则相关:
1. 为什么判定父类为调用方
你执行Field.set()操作的代码,是定义在父类TestReflection的update()方法体内的。JVM做访问权限校验时,判断依据是执行访问操作的代码所属的类,而非this指向的对象所属的类,因此本次访问的调用方会被判定为父类TestReflection。
2. 为什么能获取私有字段却无法修改
getDeclaredFields()的作用仅为查询目标类声明的所有字段元数据,该操作不涉及字段值的读写,不受访问修饰符限制,因此可以正常拿到子类的私有字段。- 字段值修改操作会触发JVM的访问控制校验:Java中私有成员仅允许在定义该成员的类的代码内部访问。示例中的
abc是匿名子类TestReflection$1定义的私有字段,只有子类自己的代码可以直接访问,父类与子类是独立的两个类,即便存在继承关系,父类也没有权限访问子类的私有成员,因此会抛出IllegalAccessException。
3. 直接实例化父类能正常运行的原因
当你直接实例化TestReflection而非构造匿名子类时,getClass()返回的就是父类本身,遍历到的foo字段是父类自己定义的私有成员,访问操作的代码也在父类内部,完全符合私有成员的访问规则,因此不需要开启setAccessible也能正常修改。
解决方案
你代码中注释的f.setAccessible(true)就是针对该场景的标准处理方案,设置为true后会绕过JVM的访问控制检查,无论字段的访问修饰符是什么、调用方是否有权限,都可以正常读写字段值。
内容的提问来源于stack exchange,提问作者Peter Kronenberg
相关产品推荐
相关产品推荐

