gpt4 book ai didi

java - 更改静态变量适用于 Primitive Wrapper 但不适用于 Primitive 类型

转载 作者:搜寻专家 更新时间:2023-10-31 19:46:06 26 4
gpt4 key购买 nike

我有一种情况,我必须更改 java 常量。

我有下面的代码工作

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);
}
}

如果我在上面运行,我得到以下输出:

Everything is 44
Everything is 33

但是如果我将 FLAG 变量更改为 int 即

public static final int FLAG = 44;

它不起作用。输出是:

Everything is 44
Everything is 44

有没有其他方法可以让它与 Primitive Type int 一起工作。

最佳答案

来自 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.

还有节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. 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); the default initial value for the type of such a field must never be observed.

这意味着 常量变量 中的编译时常量表达式 将由编译器直接放入代码中(它将被内联),而不是在运行时从最终引用中读取。

例如,如果您从 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);
}
}

你会看到 Foo 类的静态 block 没有输出,这意味着 Foo 类还没有被加载,这意味着 Foo.x 不是来自此类。事实上 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
}
}

因此,即使在运行时更改 Foo.x 的值也不会影响 Bar 类的 main 方法中打印的值。

您无法更改该机制。


可能的解决方法是使用在运行时创建的值初始化您的最终字段(它们在编译时不存在,这将防止它们成为编译时常量表达式)。所以不是

public static final String x = "foo";

尝试

public static final String x = new String("foo");

或者在原始类型的情况下使用 Unboxing 而不是

public static final int x = 42;

使用

public static final int x = new Integer(42);

关于java - 更改静态变量适用于 Primitive Wrapper 但不适用于 Primitive 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23273936/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com