2012-12-31 17 views
5

私は最近、Change private static final field using Java reflectionにつまずいてテストしたpolygenelubricants 'EverythingIsTrueクラスがうまく動作します。System.out.format("Everything is %s", false);実際にEverything is trueを印刷します。私はそれがJavaのリフレクションを使用して静的な最終フィールドを変更することはできませんか?

Everything is false 

を印刷し

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

ように、コードを変更した場合でも、誰もがなぜ知っていますか? setFinalStaticは実際に動作しますか?

答えて

13

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

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

+1

! – dty

+0

@dtyそれは無限の言葉でもあるように見えます;) –

+0

私は自分の答えを削除しました。私の回答は削除されました。 ;-) – dty

17

値をメソッド呼び出しの結果にすることで、コンパイラのインライン展開を避けることができます。唯一のより多くの言葉で - 鉱山とまったく同じ答えである

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 
+0

これは素晴らしいです!ジェネリックメソッドを使うと、非プリミティブに対してダミーメソッドを作ることができます。static T placeHolder(){return null; } ' – flakes

+0

@ mc-emperor、以前のバージョンは読みやすくなりました。 – dit

+0

@ditコンソール出力ですので、ソースコードであるかのようにフォーマットしてはいけません。 –

関連する問題