为了账号安全,请及时绑定邮箱和手机立即绑定

是否可以通过java中的反射更改默认的初始字段值?

是否可以通过java中的反射更改默认的初始字段值?

慕森卡 2021-08-19 17:52:58
假设我们有一个带有字段的类,它有一个默认的初始值,并且不会被构造函数改变,例如public class Server {  private int pingFrequency = 500;  public Server() {  }}现在我不想在构造对象之前将默认初始值更改为另一个值。原因是这个类被库使用并隐藏了对象实例。所以我只能控制对象何时构造,而不是在哪里以及如何构造。我尝试通过反射获取字段,但看不到任何更改默认值的方法Field pingFrequency =  Class.forName("Server").getDeclaredField("pingFrequency")我想我必须在类加载器中改变一些东西,但我不知道是什么以及如何改变。
查看完整描述

1 回答

?
蓝山帝景

TA贡献1843条经验 获得超7个赞

当你声明一个类时


public class Server {

  private int pingFrequency = 500;


  public Server() {

  }

}

它与


public class Server {

  private int pingFrequency;


  public Server() {

    pingFrequency = 500;

  }

}

要么


public class Server {

  private int pingFrequency;


  {

    pingFrequency = 500;

  }

  public Server() {

  }

}

事实上,所有三个变体都被编译为相同的字节码。所有字段初始值设定项和实例初始值设定项块的代码都被复制到此类的每个构造函数¹中,就在超级构造函数调用和构造函数的其余部分之间。[ JLS §12.5 ]

¹ 不委托给此类的另一个构造函数


改变赋值的唯一方法是修改所有构造函数的代码,改变赋值。这不能通过反射来完成,而只能通过字节码操作工具来完成。


请注意,当该字段已被声明时final,例如


public class Server {

  private final int pingFrequency = 500;


  public Server() {

  }

}

会有在字节码的属性,报告恒定值[ JVMS§4.7.2 ],另外的指配。但是,对于这样的编译时常量,每个普通的读取访问都将在编译时替换为常量值[ JLS §13.1 ],因此即使更改分配也不会有任何影响(也不会更改属性)[ JLS §13.4.9 ]。试图替换该字段的实际用途会引起您无法将它们与常量 number 的其他用途区分开来的问题500。


如果字段是staticand final,则根本没有赋值,则常量值属性将用于初始化字段,但是,更改它与常量实例字段的影响一样小,因为字段访问仍被替换为旧的常数值。


查看完整回答
反对 回复 2021-08-19
  • 1 回答
  • 0 关注
  • 182 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信