8

私は最近、Javaリフレクションを使用してprivate static finalフィールドを変更し、polygenelubricantsのEverythingIsTrueクラスをテストしたところ、問題なく動作し、実際にSystem.out.format("Everything is %s", false);印刷されました。Everything is trueしかし、コードを次のように変更すると

public class EverythingIsTrue {

    public static final boolean FALSE = false;

    static void setFinalStatic(Field field, Object newValue) throws Exception {
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }

    public static void main(String[] args) throws Exception {
        setFinalStatic(EverythingIsTrue.class.getField("FALSE"), true);
        System.out.format("Everything is %s", FALSE);
    }
}

それは印刷します

Everything is false

理由を知っている人はいますか?setFinalStatic は実際に機能しますか?

4

2 に答える 2

23

値をメソッド呼び出しの結果(ダミーの値であっても)にすることで、コンパイラーのインライン化を回避できます。

public class Main {
    // value is not known at compile time, so not inlined
    public static final boolean FLAG = Boolean.parseBoolean("false");

    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", true);
        System.out.printf("Everything is %s%n", FLAG);
    }
}

プリント

Everything is false
Everything is true
于 2012-12-31T13:27:55.923 に答える
16

プリミティブな static final フィールドにアクセスする場合、Java コンパイラは値が定数であると想定し、フィールドにアクセスするコードを生成する代わりに値をインライン化します。FALSEこれは、コンパイラが値を持つフィールドへの参照に置き換えることを意味しますfalse。リフレクションを使用してフィールドにアクセスすると、フィールドの値が実際に変更されていることがわかります。

オブジェクト参照の値はコンパイル時にインライン化できないため、これは非プリミティブ フィールドでは機能しません。

于 2012-12-31T13:18:43.040 に答える