2012-02-22 40 views
4

私はJava Reflectionでプライベートstatic finalフィールドを変更しようとしています。 しかしそれはちょうど失敗します。誰かがアイデアを持っていましたか?ここでJava Reflection、private static finalフィールドは何もしませんでした

は私のコードです:

public class SecuredClass { 
    private static final String securedField = "SecretData"; 
    public static String getSecretData() { return securedField; } 
} 

public class ChangeField { 
    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 
    { 
     System.out.println("Before = " + SecuredClass.getSecretData()); 

     Field stringField = SecuredClass.class.getDeclaredField("securedField"); 
     stringField.setAccessible(true); 
     setFinalStatic(stringField, "Screwed Data!"); 


     System.out.println("After = " + Java_FileMerger_Main.getSecretData()); 
    } 
} 

そして、ここでは私の出力です:

Before = SecretData 
After = SecretData 

私はヌル(System.setSecurityManagerでのSecurityManagerを削除しようとしました); しかし何も変わっていません。 私はこれが悪いことを知っていますが、私はそれを働かせたいです。 誰かが私を助けてくれることを願っています。

+0

あなたの値は 'Java_FileMerger_Main'ない' SecuredClass' – DNA

+0

ジャワから来ている「の後に」リフレクションは、クラスのバイトコードを変更するためのものではありません。この制限は、セキュリティ上の理由によるものです。たとえば 'setInt(42)'は 'SecuredClass.securedField = 42;'と同じです。 –

答えて

6

リフレクションによって最終フィールドを変更するセマンティクスは定義されていません(specification参照)。フィールドからの読み取り時に、最終フィールドへの反射書き込みが表示されることは保証されません。

特に、定数が(あなたの場合のように)割り当てられている場合、コンパイラは定数をインライン化することが多く、実行時にフィールドにアクセスすることはありません(リフレクションを使用する場合のみ)。

SecurityManagerはここでは関係ありません。リフレクションがSecurityManagerによって禁止されている場合、操作は例外をスローし、暗黙的に失敗しません。

Change private static final field using Java reflectionの質問に対する回答には、バイトコードで定数がインライン化されていることがわかります。

+0

お返事ありがとうございました! – Nicnl

1

私は上記の例にも問題がありました。 文字列としてのStringをObjectとして定義しないと、私にとってはうまくいきませんでした。

private static final String SECURED_FIELD = String.valueOf("SecretData"); 

それとも

private static final String SECURED_FIELD = new String("SecretData"); 

ない最善の解決策あなたはリテラルの恩恵を受けるしたいが、私はそれを気にする必要はありませんでした場合。

1

これには対策があります。あなたは静的に提出されたプライベート静的最終の値を設定した場合、{}、それはフィールドをインライン化しませんので、それは動作しますブロック:

private static final String MY_FIELD; 

static { 
    MY_FIELD = "SomeText" 
} 

... 

Field field = VisitorId.class.getDeclaredField("MY_FIELD"); 

field.setAccessible(true); 
field.set(field, "fakeText"); 
関連する問題