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 を使用してフィールドの修飾子を変更していないということです。では、コードはどのようにして final フィールドを変更できるのでしょうか?

4

3 に答える 3

10

これは予期される動作です。これは、実行すべきではないことです。

のドキュメントからField.set:

基になるフィールドが final である場合、この Field オブジェクトに対して setAccessible(true) が成功し、フィールドが非静的でない限り、メソッドは IllegalAccessException をスローします。このように final フィールドを設定することは、プログラムの他の部分からアクセスできるようになる前に、空白の final フィールドを持つクラスのインスタンスの逆シリアル化または再構築中にのみ意味があります。他のコンテキストで使用すると、プログラムの他の部分がこのフィールドの元の値を使用し続ける場合など、予測できない影響が生じる可能性があります。

これがあらゆる種類のセキュリティに違反していると主張したい場合は、field.setAccessible(true). 基本的に、保護はセキュリティ マネージャによって行われますが、セキュリティ マネージャを使用せずに実行していると、これを実行できなくなる可能性があります。

于 2013-04-12T05:59:59.633 に答える
2

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

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

したがって、フィールドが final であることに依存するべきではありません。

于 2013-04-12T06:27:18.903 に答える
1

いいえ、できます。特定の操作を制限したい場合は、 The Security ManagerJava SE 7 Security Documentationを読むことをお勧めします。

于 2013-04-12T06:07:41.947 に答える