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

标签 java reflection field

假设我们有一个带有字段的类,它有一个默认的初始值,并且构造函数不会更改该值,例如

public class Server {
  private int pingFrequency = 500;

  public Server() {
  }
}

现在我不想在构造对象之前将默认初始值更改为另一个值。原因是这个类被库使用并隐藏了对象实例。所以我只能控制对象何时构造,而不能控制在何处以及如何构造。

我尝试通过反射获取字段,但我没有看到任何更改默认值的方法

Field pingFrequency =  Class.forName("Server").getDeclaredField("pingFrequency")

我想我必须在类加载器中更改一些内容,但我不知道什么以及如何更改。

谢谢

最佳答案

当你声明一个类时

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() {
  }
}

事实上,所有三个变体都被编译为相同的字节码。所有字段初始值设定项和实例初始值设定项 block 的代码都会复制到此类的每个构造函数1,位于 super 构造函数调用和构造函数的其余部分之间。 [JLS §12.5 ]
¹ 不委托(delegate)给此类的另一个构造函数

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

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

public class Server {
  private final int pingFrequency = 500;

  public Server() {
  }
}

字节码中会有一个属性,报告常量值[ JVMS §4.7.2 ],另外到作业中。然而,对于这样的编译时常量,每次普通的读取访问都将被编译时的常量值替换[ JLS §13.1 ],因此即使更改分配也不会产生任何影响(也不会更改属性)[ JLS §13.4.9 ]。尝试替换该字段的实际用途会引发您无法将它们与常量 500 的其他用途区分开来的问题。

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

关于java - 是否可以通过java中的反射更改默认的初始字段值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52077533/

相关文章:

django - 在 Django 测试中检查表单错误

Java 从现有 ZipFile 中删除条目

java - Spring restTemplate 获取响应的问题

go - 使用反射填充指向结构的指针

c# - .NET 通过反射获取私有(private)属性

java - 如何使用泛型函数存储类的每个变量的值?

java - 使用 vertx embedded 和 Guice 为 Verticles 设置多个实例

java - 哈希集重复值,但我没有自定义对象

c# - 如何正确加载程序集

lucene - Orchard - 搜索和索引问题