通过反射更改私有 final 字段 [英] Changing private final fields via reflection

查看:27
本文介绍了通过反射更改私有 final 字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

class WithPrivateFinalField {
    private final String s = "I’m totally safe";
    public String toString() {
        return "s = " + s;
    }
}
WithPrivateFinalField pf = new WithPrivateFinalField();
System.out.println(pf);
Field f = pf.getClass().getDeclaredField("s");
f.setAccessible(true);
System.out.println("f.get(pf): " + f.get(pf));
f.set(pf, "No, you’re not!");
System.out.println(pf);
System.out.println(f.get(pf));

输出:

s = I’m totally safe
f.get(pf): I’m totally safe
s = I’m totally safe
No, you’re not!

为什么会这样,能解释一下吗?第一个打印告诉我们私有s"字段没有改变,正如我所期望的.但是如果我们通过反射得到这个字段,第二个打印显示,它被更新了.

Why does it work by this way, can you please explain? The first print tells us that the private "s" field has not been changed, as I expect. But if we get the field via reflection, the second print shows, it is updated.

推荐答案

这个答案对这个话题非常详尽.

JLS 17.5.3 最终字段的后续修改

JLS 17.5.3 Subsequent Modification of Final Fields

即便如此,仍有许多并发症.如果最后一个字段是在字段声明中初始化为编译时常量,可能不会观察到最终字段的更改,因为使用该字段final 字段在编译时替换为编译时常数.

Even then, there are a number of complications. If a final field is initialized to a compile-time constant in the field declaration, changes to the final field may not be observed, since uses of that final field are replaced at compile time with the compile-time constant.

但是,如果您非常仔细地阅读上面的段落,您可能会在这里找到解决方法(在构造函数中而不是在字段定义中设置 private final 字段):

But, if you read the paragraph above very carefully, you may find a way around here (set the private final field in the constructor instead of in the field definition):

import java.lang.reflect.Field;


public class Test {

  public static void main(String[] args) throws Exception {
    WithPrivateFinalField pf = new WithPrivateFinalField();
    System.out.println(pf);
    Field f = pf.getClass().getDeclaredField("s");
    f.setAccessible(true);
    System.out.println("f.get(pf): " + f.get(pf));
    f.set(pf, "No, you’re not!");
    System.out.println(pf);
    System.out.println("f.get(pf): " + f.get(pf));
  }

  private class WithPrivateFinalField {
    private final String s;

    public WithPrivateFinalField() {
      this.s = "I’m totally safe";
    }
    public String toString() {
      return "s = " + s;
    }
  }

}

输出如下:

s = I’m totally safe
f.get(pf): I’m totally safe
s = No, you’re not!
f.get(pf): No, you’re not!

希望这会有所帮助.

这篇关于通过反射更改私有 final 字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆