2016-01-16 4 views
10

Reflectionで最終フィールドを変更した後、そのフィールドを返すメソッドは常に古い値を返すというのは非常に奇妙なことに気付きました。これはJITコンパイラのせいかもしれないと思います。JITでコンパイルされた最終値を変更する

public class Main 
{ 
private static final Main m = new Main(); 
public static Main getM() 
{ 
    return m; 
} 

public static void main(String args[]) throws Exception 
{ 
    Main m = getM(); 
    int x = 0; 
    for(int i = 0;i<10000000;i++) 
    { 
     if(getM().equals(m)) 
      x ++; 
    } 
    Field f = Main.class.getDeclaredField("m"); 
    f.setAccessible(true); 
    removeFinal(f); 
    Main main1 = new Main(); 
    f.set(null, main1); 
    Main main2 = (Main) f.get(null); 
    Main main3 = getM(); 
    System.out.println(main1.toString()); 
    System.out.println(main2.toString()); 
    System.out.println(main3.toString()); 
} 

private static void removeFinal(Field field) throws NoSuchFieldException, IllegalAccessException 
{ 
    Field modifiersField = Field.class.getDeclaredField("modifiers"); 
    modifiersField.setAccessible(true); 
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 
} 
} 

結果は次のとおりです:ここで

は、サンプルプログラムである、私は疑問に思って

[email protected] 
[email protected] 
[email protected] 

、どのように私はGETM()の戻り値は、更新することができますか?

+3

キーワード 'final'は、コンパイラがインライン化できるようにします。なぜあなたはこれをする必要がありますか? –

+0

JITを強制的に再コンパイルする方法はありますか? – user3009344

+1

JITではなくjavacコンパイラです。 –

答えて

11

私はどのようにしてgetM()が更新された値を返すのか疑問に思っていますか?

決勝では、あなたはできません。 「古い」値を返すことは、正当な振る舞いです。JLS 17.5.3

それでも多くの合併症があります。最終フィールドが 宣言の定数式(15.28)に初期化されている場合、最終フィールドの変更は無視されます。表現。

もう1つの問題は、本明細書が最終フィールドの積極的な最適化を可能にすることである。スレッド内では、 の最後のフィールドの変更は、コンストラクタ内で行われない最後の フィールドの変更と並び替えることができます。

この章に含まれている参考例を参照してください。

この条項を克服しようとすると、スタックの下にオプティマイザを混乱させる必要があり、せいぜい壊れやすいだけです。フィールドを変更することを選択している場合、定義によって、これらのフィールドは最終的なものではありません。これをパフォーマンス上の理由から望むなら(本当ですか?)、JSR 292は"almost final"構造を行うための仕組みを提供します。

+0

私のアプリケーション内の何かが壊れたときに、アプリケーションを再起動せずに新しい小さなjarファイルをロードすることで問題を一時的に修正/隠す方法があります静的メソッドへのアクセス。時には私は何かを修正するために最終的なフィールドを変更する必要があります。このような場合、通常は反射が正常に機能しますが、その問題のために時には反映されません。だから私はそれを克服する方法はないと思う。 – user3009344

1

本当にその値を変更したい場合は、そのクラスをラップしてgetterを上書きすることができます。

多分あなたは "委任"/"プロキシ"パターンについて聞いたことがあります。

関連する問題