假设我们有一个带有字段的类,它有一个默认的初始值,并且构造函数不会更改该值,例如
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
的其他用途区分开来的问题。
如果字段是static
和final
,则根本没有赋值,常量值属性将用于初始化字段,但是,更改它会产生与常量实例字段的影响一样小,因为字段访问仍然被旧的常量值替换。
关于java - 是否可以通过java中的反射更改默认的初始字段值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52077533/