38

これは、指定されたセットの変更不可能なビューを返すことがわかりますが、これを実現するために修飾子をCollections.unmodifiableSet使用できない理由がわかりません。final

私の理解ではfinal、定数を宣言します:変更できないもの。したがって、セットが定数として宣言されている場合、それを変更することはできません。セットから何も削除できず、何も追加できません。

なぜ必要なのCollections.unmodifiableSetですか?

4

5 に答える 5

75

final変更できないオブジェクト参照を宣言します。例:

private final Foo something = new Foo();

新しいFooを作成し、参照をに配置しsomethingます。somethingその後、の別のインスタンスを指すように変更することはできませんFoo

これは、オブジェクトの内部状態の変更を妨げるものではありません。Foo関連するスコープにアクセスできるメソッドは、引き続き呼び出すことができます。これらのメソッドの1つ以上がそのオブジェクトの内部状態を変更する場合、それfinalを防ぐことはできません。

そのため、次のようになります。

private final Set<String> fixed = new HashSet<String>();

追加または変更できないを作成しません。これは、そのインスタンスのみを参照することをSet意味します。fixed

対照的に、次のことを行います。

private Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );

またはを呼び出そうとするSetとスローされるインスタンスを作成します。たとえば、オブジェクト自体がその内部状態を保護し、変更されないようにします。UnsupportedOperationExceptionfixed.add()fixed.remove()

完全を期すために:

private final Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );

Set内部状態を変更できないaのインスタンスを作成します。これはfixed、そのセットのインスタンスのみを指すことも意味します。

プリミティブの定数を作成するために使用できる理由finalは、値を変更できないという事実に基づいています。fixed上記は単なる参照であり、変更できないアドレスを含む変数であることを忘れないでください。ええと、プリミティブの場合、例えば

private final int ANSWER = 42;

の値はANSWER42ANSWERです。変更できないため、値は42になります。

すべての線をぼかす例は次のとおりです。

private final String QUESTION = "The ultimate question";

上記のルールに従い、「究極の質問」を表すQUESTIONインスタンスのアドレスが含まれており、そのアドレスは変更できません。Stringここで覚えておくべきことは、Stringそれ自体が不変であるということです。それを変更するインスタンスに対しては何もできません。Stringそうでなければ変更する操作(replacesubstringなど)は、のまったく異なるインスタンスへの参照を返しますString

于 2010-03-10T20:03:29.753 に答える
18

final変数が表すオブジェクトへの参照が変更できないことを保証するだけで、オブジェクトのインスタンスとその可変性に対しては何もしません。

final Set s = new Set();二度とできないことを保証するだけですs = new Set();。セットを変更できないようにするわけではありません。そもそも何も追加できなかった場合です。したがって、明確にするために、参照が指すオブジェクトではなく、変数参照finalにのみ影響します。

私は次のことができます:

final List<String> l = new ArrayList<String>();
l.add("hello");
l.add("world");
l.remove(0);

しかし、私はこれを行うことはできません。

l = new ArrayList<String>();

final変数lが指すものを変更できないためです。

コレクションコンテナのスレッドを安全にするには、次の3つのいずれかを実行する必要があります。

java.util.Collections.syncronizedXXX();

また

java.util.Collections.unmodifiableXXX();

または、から適切なコンテナの1つを使用しjava.util.concurrency.* packageます。

Personオブジェクトがあり、それを実行した場合、別のオブジェクトを指すようにfinal Person p = new Person("me");再割り当てすることはできません。私はまだすることができますpPersonp.setFirstName("you");

状況を混乱させるのは

final int PI = 3.14;
final String greeting = "Hello World!";

C ++のようconstに見えますが、実際には、それらが指すオブジェクトは本質的に不変/変更不可能です。オブジェクトの内部状態を変更できるミューテイタメソッドを持つコンテナまたはオブジェクトは、それらのオブジェクトへの参照constだけではなく、別のオブジェクトを参照するために再割り当てすることもできません。final

于 2010-03-10T20:01:58.163 に答える
4

元のCollections.unmodifiableSet(Set<? extends T>)セットにラッパーを作成します。このラッパーセットは変更できません。ただし、元のセットは変更できます。

例:

 Set<String> actualSet=new HashSet<String>(); //Creating set

いくつかの要素を追加する

actualSet.add("aaa");
actualSet.add("bbb");

追加された要素を印刷する

System.out.println(actualSet);   //[aaa, bbb]

を変更不可能なセットに入れ、actualSet新しいreference()に割り当てwrapperSetます。

Set<String> wrapperSet=Collections.unmodifiableSet(orginalSet);

wrapperSetを印刷します。actualSet値があります

System.out.println(wrapperSet);   //[aaa, bbb]

の1つの要素を削除/追加してみましょうwrapperSet

wrapperSet.remove("aaa");   //UnSupportedOperationException 

にもう1つの要素を追加しますactualSet

    actualSet .add("ccc");

印刷actualSetしてwrapperSet。両方のセット値は同じです。したがって、実際のセットで要素を追加/削除すると、変更はラッパーセットにも反映されます。

    System.out.println(actualSet);  //[aaa, ccc, bbb]
    System.out.println(wrapperSet);  // [aaa, ccc, bbb]

使用法:

これ Collections.unmodifiableSet(Set<? extends T>)は、任意のオブジェクトのSetのgetterメソッドの変更を防ぐために使用されます。言わせて

public class Department{

    private Set<User> users=new HashSet<User>();

    public Set<User> getUsers(){
        return Collections.unmodifiableSet(users); 
    }
}
于 2014-03-20T14:39:44.913 に答える
3

final(C ++スタイル)ではありませんconst。C ++とは異なり、Javaにはconst-methodsなどがなく、オブジェクトを変更できるメソッドはfinal参照を介して呼び出すことができます。

Collections.unmodifiable*は、関連するコレクションの読み取り専用性を(コンパイル時ではなく実行時にのみ)強制するラッパーです。

于 2010-03-10T20:03:53.543 に答える
1

できることとできないことを要約します。

準備:

private Set<String> words = new HashSet<>(Arrays.asList("existing word"));

参照による最終

private final Set<String> words = new HashSet<>();

できます

words.add("new word");

できません

words = new HashSet<>(); //compilation error

参照により最終的であり、収集により変更できません。

プライベートファイナルセットワード=Collections.unmodizableSet(words);

できます

String word = words.iterator().next();

できません

words = new HashSet<>(); // compilation error
words.add("new word"); // runtime error UnsupportedOperationException

参照により最終的であり、コレクションによって変更することはできませんが、コレクションのオブジェクトとして相互に使用できます。

ただし、相互オブジェクトを含むコレクションがある場合は、そのオブジェクトの内部状態を変更できます。

 class A {
       public int a; //mutable field. I can change it after initialization
       public A(int a) {this.a = a;}
     }

 private final Set<A> set = Collections.unmodifiableSet(Arrays.asList(new A(25)));

まだできません

set = new HashSet<>(); // compilation error
set.add(new A(777)); // runtime error UnsupportedOperationException

しかし、できます

 A custom = words.iterator().next(); //here custom.a = 25;
 custom.a = 777; //here first element of **final, unmodifible** collection 
    //was changed from 25 to 777
于 2018-07-13T09:19:58.583 に答える