Use*_*291 1 java instrumentation bytecode java-bytecode-asm soot
比方说我有一个
class Foo(){
public final static int bar = -1;
}
Run Code Online (Sandbox Code Playgroud)
反汇编的字节码看起来像这样
super public class Foo
version 51:0
{
public static final Field bar:I = int -1;
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
} // end Class Foo
Run Code Online (Sandbox Code Playgroud)
是的,这让我感到惊讶.我本来期望有一个<clinit>包含赋值的方法bar,然后我可以替换它.(当我删除final修饰符时会发生这种情况.)
如何更改final字段的值?我该怎么做?
你的期望是不正确的.static final int用整数文字初始化的A 将是编译时常量.编译时常量由字节码编译器内联.
无法在运行时更改值或使用字节码修改.字节码编译器所做的内联无法解开.重新编译类及其依赖类是更改编译时常量值的唯一可行方法.
请注意,这不仅仅是Java编译器实现的一个不方便的工件.编译时常量的这种处理是由JLS强制执行的.例如,JLS 17.5.3说明了尝试final使用反射更改编译时常量:
"如果
final在字段声明中将字段初始化为常量表达式(第15.28节),则final可能无法观察到对字段的更改,因为final在编译时将该字段的使用替换为常量表达式的值."
换句话说,对更改的反射API调用Foo.bar似乎成功,但内联的实际值不会更改.事实上,唯一可能看到更新值的代码是Foo.bar使用反射读取的代码!
一种可能的解决方法是以一种使其不是编译时常量的方式声明常量.例如:
class Foo() {
public final static int bar = Integer.parseInt("-1");
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
612 次 |
| 最近记录: |