[英]Changing static variable works Primitive Wrapper but not with Primitive type
I have a situation where I have to change java constant. 我有一种情况,我必须改变java常量。
I have below code working 我有以下代码工作
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class Main {
public static final Integer FLAG = 44;
static void setFinalStatic(Class<?> clazz, String fieldName, Object newValue) throws NoSuchFieldException, IllegalAccessException {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
Field modifiers = field.getClass().getDeclaredField("modifiers");
modifiers.setAccessible(true);
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, newValue);
}
public static void main(String... args) throws Exception {
System.out.printf("Everything is %s%n", FLAG);
setFinalStatic(Main.class, "FLAG", 33);
System.out.printf("Everything is %s%n", FLAG);
}
}
If I run above , I get following output: 如果我在上面运行,我得到以下输出:
Everything is 44
Everything is 33
But if I change FLAG
variable to int ie 但是如果我将
FLAG
变量更改为int ie
public static final int FLAG = 44;
It does not work. 这是行不通的。 The output is :
输出是:
Everything is 44
Everything is 44
Is there any other way to make it work with Primitive
Type int
. 有没有其他方法可以使它与
Primitive
Type int
。
From jls-4.12.4 从jls-4.12.4
A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28) , is called a
constant variable
.原始类型或类型String的变量是final,并使用编译时常量表达式(第15.28节)初始化,称为
constant variable
。
Also section 13.1 says (emphasis mine) 第13.1节也说(强调我的)
3.. References to fields that are constant variables (§4.12.4) are resolved at compile time to the constant value that is denoted .
3 .. 对常量变量字段(第4.12.4节)的引用在编译时被解析为表示的常量值 。 No reference to such a field should be present in the code in a binary file (except in the class or interface containing the field, which will have code to initialize it).
二进制文件中的代码中不应存在对此类字段的引用(包含该字段的类或接口除外,该字段将具有初始化它的代码)。 Such a field must always appear to have been initialized (§12.4.2);
这样的字段必须总是看似已经初始化(§12.4.2); the default initial value for the type of such a field must never be observed.
绝不能遵守此类字段类型的默认初始值。
It means that compile-time constant expression from constant variables will be put directly in code by compiler (it will be inlined) not read from final reference at runtime. 这意味着来自常量变量的 编译 时常量 表达式将由编译器直接放入代码中(它将被内联),而不是在运行时从最终引用中读取。
For instance if you execute main
method from Bar
class 例如,如果您从
Bar
类执行main
方法
class Foo{
static{
System.out.println("test if class will be loaded");
}
public static final int x = 42;
}
class Bar{
public static void main(String [] args){
System.out.println(Foo.x);
}
}
you will see no output from static block of Foo
class which means Foo
class hasn't been loaded, which means that value of Foo.x
didn't come from this class. 您将看不到
Foo
类的静态块的输出,这意味着Foo
类尚未加载,这意味着Foo.x
值不是来自此类。 In fact Bar
was compiled this way 实际上
Bar
就是这样编译的
class Bar{
public static void main(String [] args){
System.out.println(42); // reference Foo.x will be removed by compiler
// and replaced with actual value because
// compiler assumes that value can't/shouldn't
// change at runtime
}
}
So even changing value of Foo.x
at runtime will not affect value printed in main
method in Bar
class. 因此,即使在运行时更改
Foo.x
值也不会影响在Bar
类的main
方法中打印的值。
You can't change that mechanism. 你无法改变这种机制。
Possible way around would be initializing your final fields with values created at runtime time (they wouldn't exist at compile time, which will prevent them from being compile-time constant expressions ). 可能的方法是使用在运行时创建的值初始化最终字段(它们在编译时不存在,这将阻止它们成为编译时常量表达式 )。 So instead of
而不是
public static final String x = "foo";
try 尝试
public static final String x = new String("foo");
or in case of primitive types use Unboxing like instead of 或者在原始类型的情况下使用取消装箱而不是
public static final int x = 42;
use 使用
public static final int x = new Integer(42);
Primitive types get inlined. 原始类型内联。
In fact even non-primitive constants, when imported into other classes, will be copied, and the import forgotten. 事实上,甚至非原始常量,当导入到其他类时,将被复制,并且导入被遗忘。 So there it will not work either.
所以它也不会起作用。 Only for constant caches, like the string pool, and Integer (Integer.valueOf(13)) caches you may overwrite their values.
仅对于常量高速缓存(如字符串池)和Integer(Integer.valueOf(13))高速缓存,您可以覆盖它们的值。
This happens because static final fields of primitive or String type get inlined during compile time. 这是因为在编译期间内联或String类型的静态final字段被内联。 The main method will looks something like this after compilation and de-compilation
在编译和反编译之后,main方法看起来像这样
public static void main(String... args) throws Exception {
System.out.printf("Everything is %s%n", 44);
setFinalStatic(Main.class, "FLAG", 33);
System.out.printf("Everything is %s%n", 44);
}
because FLAG gets replaced with actual value in compile-time. 因为FLAG在编译时被实际值替换。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.