わかります - Collections.unmodifiableSet
は、指定されたセットの変更不可能なビューを返しますが、final
修飾子を使用してこれを実行できない理由がわかりません。
私の理解では、final
は定数を宣言します。変更できないものです。したがって、セットが定数として宣言されている場合、そのセットを変更することはできません。セットから削除したり、追加したりすることはできません。
なぜCollections.unmodifiableSet
?
final
は、変更できないオブジェクト参照を宣言します。
_private final Foo something = new Foo();
_
新しいFoo
を作成し、参照をsomething
に配置します。その後、something
を変更してFoo
の別のインスタンスを指すようにすることはできません。
notはオブジェクトの内部状態の変更を防ぎます。関連するスコープにアクセスできるFoo
のメソッドを呼び出すことができます。これらのメソッドの1つ以上がそのオブジェクトの内部状態を変更する場合、final
はそれを防止しません。
そのため、次のとおりです。
_private final Set<String> fixed = new HashSet<String>();
_
しないnot追加または変更できないSet
を作成します。これは、fixed
がそのインスタンスのみを参照することを意味します。
対照的に、次のようにします。
_private Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
_
たとえば、fixed.add()
またはfixed.remove()
を呼び出そうとした場合にSet
をスローするUnsupportedOperationException
のインスタンスを作成します。たとえば、オブジェクト自体が内部状態を保護し、変更されないようにします。
完全を期すために:
_private final Set<String> fixed = Collections.unmodifiableSet( new HashSet<String>() );
_
内部状態を変更できないSet
のインスタンスを作成します。また、fixed
がそのセットのインスタンスのみを指すことも意味します。
final
を使用してプリミティブの定数を作成できる理由は、値を変更できないという事実に基づいています。上記のfixed
は単なる参照であり、変更できないアドレスを含む変数であることを思い出してください。まあ、プリミティブ、例えば.
_private final int ANSWER = 42;
_
ANSWER
の値は42です。ANSWER
は変更できないため、値が42になるだけです。
すべての線をぼかす例は次のようになります:
_private final String QUESTION = "The ultimate question";
_
上記のルールに従って、QUESTION
には、「究極の質問」を表すString
のインスタンスのアドレスが含まれ、そのアドレスは変更できません。ここで覚えておくべきことは、String
自体は不変であることです。これを変更するString
のインスタンスに対しては何も実行できません。また、そうしないと実行される操作(replace
、substring
など)は、まったく異なる参照を返します。 String
のインスタンス。
final
は、変数が表すオブジェクトへのreferenceが変更できないことのみを保証します。オブジェクトのインスタンスとその可変性に対しては何もしません。
final Set s = new Set();
は、もう一度s = new Set();
を実行できないことを保証するだけです。それはセットを変更不可能にしません、もしあなたがそれに最初に何かを追加することができなかった場合。つまり、明確にするために、final
は変数referenceにのみ影響し、参照が指すオブジェクトには影響しません。
私は次のことができます:
_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
ではありません。これらのオブジェクトへのreferenceはfinal
であり、再割り当てできません参照別のオブジェクト。
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
の1つの要素を削除/追加してみましょう。
_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>)
は、オブジェクトのSetのゲッターメソッドが変更されないようにするために使用されます。言わせて
_public class Department{
private Set<User> users=new HashSet<User>();
public Set<User> getUsers(){
return Collections.unmodifiableSet(users);
}
}
_
final
は(C++スタイル)const
ではありません。 C++とは異なり、Javaにはconst
- methodsなどはなく、オブジェクトを変更できるメソッドはfinal
参照を介して呼び出すことができます。
Collections.unmodifiable*
は、関係するコレクションの読み取り専用を(コンパイル時ではなく実行時にのみ)強制するラッパーです。
できることとできないことを要約します。
準備:
private Set<String> words = new HashSet<>(Arrays.asList("existing Word"));
private final Set<String> words = new HashSet<>();
can:
words.add("new Word");
できない:
words = new HashSet<>(); //compilation error
private final Set words = Collections.unmodifiableSet(words);
can:
String Word = words.iterator().next();
できない:
words = new HashSet<>(); // compilation error
words.add("new Word"); // runtime error UnsupportedOperationException
しかしmutual オブジェクトを含むコレクションがある場合、そのオブジェクトの内部状態を変更できます。
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