2013-04-12 4 views
6

不変性を段階的に示すためにクラスを設計したいと思います。続き最終変数をリフレクションから保護する

は今、私はまだ、次のコードを使用することにより、リフレクションを使用して突破することができます単純なクラス

public class ImmutableWithoutMutator { 
    private final String firstName; 
    private final String lastName; 
    private final int age; 

    public ImmutableWithoutMutator(final String firstName, final String lastName, final int age) { 
     this.firstName = firstName; 
     this.lastName = lastName; 
     this.age = age; 
    } 

    @Override 
    public String toString() { 
     return String.format(
       "ImmutableWithoutMutator [age=%s, firstName=%s, lastName=%s]", 
       age, firstName, lastName); 
    } 
} 

です。

import java.lang.reflect.Field; 

public class BreakImmutableUsingReflection { 
    public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { 
     ImmutableWithoutMutator immMutator = new ImmutableWithoutMutator(
       "firstName", "lastName", 2400); 
     System.out.println(immMutator); 

     // now lets try changing value using reflection 
     Field f = ImmutableWithoutMutator.class.getDeclaredField("age"); 
     f.setAccessible(true); 
     f.set(immMutator, 2000); 

     System.out.println(immMutator); 
    } 
} 

私の質問は、リフレクションAPIを使用してフィールドの修飾語を変更していないことです。それでは、コードが最終的なフィールドをどのように変えることができるのでしょうか?

+0

可能な複製http://stackoverflow.com/questions/1615163/modifying-final-fields-in-java?rq=1 – Patashu

答えて

10

これは予想される動作です。これはすべきではありません。 Field.setのドキュメントから

:(真)setAccessibleこのFieldオブジェクトのために成功していない限り、

基本となるフィールドがfinalである場合には、メソッドはIllegalAccessExceptionをスローし、フィールドが非静的です。このように最終フィールドを設定することは、プログラムの他の部分がアクセスできるようになる前に、空白の最終フィールドを持つクラスのインスタンスを逆シリアル化または再構築する場合にのみ意味を持ちます。他のコンテキストでの使用は、プログラムの他の部分がこのフィールドの元の値を引き続き使用する場合を含めて、予期しない結果をもたらす可能性があります。あなたは、これはセキュリティのすべての種類に違反すると主張したい場合

は今、あなたはあなたが正気field.setAccessible(true)を呼び出すための十分な権限で実行されるように信頼していないコードを持っている理由を自問する必要があります。基本的にはセキュリティマネージャーが保護していますが、セキュリティマネージャーがなくてもこれをやめないと実行している場合は、を足で撃ってください。

+4

'if(author.getName()。equals(" Jon Skeet ")){ this.upvote(); } else {this.readAnswer();} } ' –

+0

@ Jon-skeet詳細な説明をありがとう。 – Vivek

2

SecurityManagerを使用してsetAccessibleから保護することができます。 hereのように、コマンドラインで指定するか、動的に作成することができます。

しかし、リフレクションから保護しても、コードはASMのようなバイトコード変更ライブラリに対して保護されません。

あなたはフィールドが最終的であることに頼るべきではありません。

関連する問題