Java では Collections.unmodifiableSet() は何をしますか?
-
19-09-2019 - |
質問
わかります Collections.unmodifiableSet
指定されたセットの変更不可能なビューを返しますが、なぜ単に使用できないのか理解できません final
これを達成するための修飾子。
私の理解では、 final
定数を宣言します。変更できないもの。したがって、セットが定数として宣言されている場合は変更できません。セットから何も削除したり、何も追加したりすることはできません。
なぜ必要なのか Collections.unmodifiableSet
?
解決
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>() );
は1つが、例えば、Set
又はUnsupportedOperationException
をコールしようとした場合fixed.add()
をスローしますfixed.remove()
のインスタンス作成 - オブジェクト自体がその内部状態を保護し、変更されてからそれを防止するに
完全酒の場合:
private final Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
は、その内部状態を変更することができませんSet
のインスタンスを作成し、またfixed
にしかそのセットのインスタンスを指すことを意味します。
final
はプリミティブの定数を作成するために使用することができるという理由は、値を変更することができないという事実に基づいています。変更することはできませんアドレスを含む変数 - ちょうど参照した上でそのfixed
を覚えておいてください。まあ、プリミティブの、例えばます。
private final int ANSWER = 42;
ANSWER
の値はANSWER
を変更することはできませんので42は、それだけで今までに値42を持つことになります。
すべてのラインをぼかし例は、このようになります:
private final String QUESTION = "The ultimate question";
上記のルールに従って、QUESTION
は「究極の質問」を表すString
のインスタンスのアドレスが含まれ、そのアドレスを変更することはできません。ここで覚えておくべき事はそのString
自体は不変である - あなたはそれを変更String
のインスタンスに何もできないし、そうでない場合(などreplace
、substring
、など)、そうであろう任意の操作を参照し、全く異なるのを返しますString
のインスタンスます。
他のヒント
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();
または
java.util.concurrency.* package
から適当な容器のいずれかを使用します。
Person
オブジェクトを持っていたし、final Person p = new Person("me");
なかった場合は、それは私が別のp
オブジェクトを指すようにPerson
を再割り当てすることはできませんを意味します。私はまだp.setFirstName("you");
を行うことができます。
どのような状況が混乱することになる。
final int PI = 3.14;
final String greeting = "Hello World!";
実際に彼らが指すオブジェクトは本質的に変更不可能/不変であるとき、C ++でconst
のように見えます。オブジェクトの内部状態を変化させることができるミューテータ方法とコンテナまたはオブジェクトがconst
あるそれらのオブジェクトにだけの参照]をfinal
されていないとの参照の他の目的に再割り当てすることはできませんます。
final
const
ではありません。 C ++とは異なり、Javaはconst
-方法またはそのようなものを持っていない、とオブジェクトを変更することができます方法はfinal
の参照を経由して呼び出すことができます。
Collections.unmodifiable*
は(だけではなく、コンパイル時に実行時に)強制ラッパーコレクションの読み取り専用らしです心配ます。
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
を入れて、新しい基準(wrapperSet
)に割り当てられます。
Set<String> wrapperSet=Collections.unmodifiableSet(orginalSet);
wrapperSetを印刷します。そう、それはactualSet
値を持つことになります。
System.out.println(wrapperSet); //[aaa, bbb]
wrapperSet
上の一つの要素を追加/削除しようとすることができます。
wrapperSet.remove("aaa"); //UnSupportedOperationException
actualSet
に1つの以上の要素を追加します。
actualSet .add("ccc");
印刷actualSet
とwrapperSet
。両方のセットの値は同じです。あなたが追加した場合ので、/変更が同様に設定されたラッパーに反映される実際のセット上の任意の要素を削除します。
System.out.println(actualSet); //[aaa, ccc, bbb]
System.out.println(wrapperSet); // [aaa, ccc, bbb]
の使用方法:の
このCollections.unmodifiableSet(Set<? extends T>)
は、任意のオブジェクトのセットのgetterメソッドの変更を防ぐために使用されます。しましょう。
public class Department{
private Set<User> users=new HashSet<User>();
public Set<User> getUsers(){
return Collections.unmodifiableSet(users);
}
}
できることとできないことを要約すると、次のようになります。
準備:
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
参照による最終的なものであり、コレクションによる変更はできません。
privatefinal Setwords = Collections.unmodifiableSet(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