更改静态变量可以使用原始包装,但不能使用原始类型

Mak*_*kky 5 java reflection primitive class

我有一种情况,我必须改变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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Everything is 44
Everything is 33
Run Code Online (Sandbox Code Playgroud)

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

public static final int FLAG = 44;
Run Code Online (Sandbox Code Playgroud)

这是行不通的.输出是:

Everything is 44
Everything is 44
Run Code Online (Sandbox Code Playgroud)

有没有其他方法可以使它与PrimitiveType一起使用int.

Psh*_*emo 6

jls-4.12.4

原始类型或类型String的变量,最终并使用编译时常量表达式(第15.28节)初始化,称为a constant variable.

13.1节也说(强调我的)

3 .. 对常量变量字段(第4.12.4节)的引用在编译时被解析为表示的常量值.二进制文件中的代码中不应存在对此类字段的引用(包含该字段的类或接口除外,该字段将具有初始化它的代码).这样的字段必须总是看似已经初始化(§12.4.2); 绝不能遵守此类字段类型的默认初始值.

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

例如,如果您mainBar类执行方法

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

您将看不到Foo类的静态块的输出,这意味着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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

你无法改变这种机制.


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

public static final String x = "foo";
Run Code Online (Sandbox Code Playgroud)

尝试

public static final String x = new String("foo");
Run Code Online (Sandbox Code Playgroud)

或者在原始类型的情况下使用取消装箱而不是

public static final int x = 42;
Run Code Online (Sandbox Code Playgroud)

使用

public static final int x = new Integer(42);
Run Code Online (Sandbox Code Playgroud)