以下からのコレクションフレームワークの概要:
変更操作をサポートしていないコレクションは、(のような
add
、remove
とclear
)と呼ばれている変更不可能。変更不可でないコレクションは変更可能です。
Collection
オブジェクトの変更が表示されないことをさらに保証するコレクションは、不変と呼ばれます。不変でないコレクションは変更可能です。
区別がつかない。ここで変更不可と不変の
違いは何ですか?
以下からのコレクションフレームワークの概要:
変更操作をサポートしていないコレクションは、(のような
add
、remove
とclear
)と呼ばれている変更不可能。変更不可でないコレクションは変更可能です。
Collection
オブジェクトの変更が表示されないことをさらに保証するコレクションは、不変と呼ばれます。不変でないコレクションは変更可能です。
区別がつかない。ここで変更不可と不変の
違いは何ですか?
回答:
多くの場合、変更不可能なコレクションは、他のコードがにアクセスできる変更可能なコレクションのラッパーです。そうしながら、あなたはあなたが唯一の変更不可能なコレクションへの参照を持っている場合、それを変更することはできません、あなたは変わらない内容に依存することはできません。
不変コレクションは、その保証は何も任意のより多くのコレクションを変更することはできません。変更可能なコレクションをラップする場合は、他のコードがその変更可能なコレクションにアクセスできないようにします。コードがコレクションに含まれる参照を含むオブジェクトを変更することはできませんが、オブジェクト自体は変更可能である可能性があることに注意してくださいStringBuilder
。
基本的に、違いは、他のコードが背後でコレクションを変更できるかどうかです。
list
ます。何かが後で呼び出すことができる場合はlist.add(10)
、次にcoll
その変更が反映されますので、いや、私はそれが不変で呼び出すことはありません。
基本的にunModifiable
コレクションはビューなので、間接的には変更可能な他の参照から「変更」される可能性があります。また、別のコレクションの読み取り専用ビューとして、ソースコレクションが変更されると、Modifiableコレクションは常に最新の値で表示されます。
ただし、immutable
コレクションは別のコレクションの読み取り専用コピーとして扱うことができ、変更することはできません。この場合、ソースコレクションが変更されても、不変コレクションには変更が反映されません
この違いを視覚化するためのテストケースを次に示します。
@Test
public void testList() {
List<String> modifiableList = new ArrayList<String>();
modifiableList.add("a");
System.out.println("modifiableList:"+modifiableList);
System.out.println("--");
//unModifiableList
assertEquals(1, modifiableList.size());
List<String> unModifiableList=Collections.unmodifiableList(
modifiableList);
modifiableList.add("b");
boolean exceptionThrown=false;
try {
unModifiableList.add("b");
fail("add supported for unModifiableList!!");
} catch (UnsupportedOperationException e) {
exceptionThrown=true;
System.out.println("unModifiableList.add() not supported");
}
assertTrue(exceptionThrown);
System.out.println("modifiableList:"+modifiableList);
System.out.println("unModifiableList:"+unModifiableList);
assertEquals(2, modifiableList.size());
assertEquals(2, unModifiableList.size());
System.out.println("--");
//immutableList
List<String> immutableList=Collections.unmodifiableList(
new ArrayList<String>(modifiableList));
modifiableList.add("c");
exceptionThrown=false;
try {
immutableList.add("c");
fail("add supported for immutableList!!");
} catch (UnsupportedOperationException e) {
exceptionThrown=true;
System.out.println("immutableList.add() not supported");
}
assertTrue(exceptionThrown);
System.out.println("modifiableList:"+modifiableList);
System.out.println("unModifiableList:"+unModifiableList);
System.out.println("immutableList:"+immutableList);
System.out.println("--");
assertEquals(3, modifiableList.size());
assertEquals(3, unModifiableList.size());
assertEquals(2, immutableList.size());
}
出力
modifiableList:[a]
--
unModifiableList.add() not supported
modifiableList:[a, b]
unModifiableList:[a, b]
--
immutableList.add() not supported
modifiableList:[a, b, c]
unModifiableList:[a, b, c]
immutableList:[a, b]
--
modifiableList
とunModifiableList
増加しているimmutableList
サイズが変更されていない
new ArrayList<String>(modifiableList)
immutableList への参照がないため変更できません
new ArrayList<String>(modifiableList)
ためのはnew
?ありがとう。
主な違いは、可変コレクションの所有者が他のコードにコレクションへのアクセスを提供することを望むかもしれないが、他のコードがコレクションを変更することを許可しないインターフェースを介してそのアクセスを提供することです(その機能を予約している間)所有コードに)。そのため、コレクションは不変ではありませんが、特定のユーザーはコレクションを変更することが許可されていません。
OracleのJava Collection Wrapperチュートリアルでは、これを強調しています(強調を追加)。
変更不可能なラッパーには、主に次の2つの用途があります。
- コレクションが作成された後でコレクションを不変にすること。この場合、バッキングコレクションへの参照を維持しないことをお勧めします。これは絶対に不変性を保証します。
- 特定のクライアントにデータ構造への読み取り専用アクセスを許可する。バッキングコレクションへの参照は保持しますが、ラッパーへの参照を渡します。このようにして、フルアクセスを維持しながら、クライアントは外観を変更できません。
JDK Unmodifiable*
とグアバについて話をしている場合Immutable*
、実際には違いもパフォーマンスにあります。不変コレクションは、通常のコレクションのラッパーではない場合(JDK実装はラッパー)、高速でメモリ効率も高くなります。
グアバチームの引用:
JDKはCollections.unmodifiableXXXメソッドを提供しますが、私たちの意見では、これらは
<...>
List.of(...)
実際に2回コピーされます。
Java™チュートリアルを引用するには:
ラップされたコレクションに機能を追加する同期ラッパーとは異なり、変更できないラッパーは機能を奪います。特に、コレクションを変更するすべての操作をインターセプトしてUnsupportedOperationExceptionをスローすることにより、コレクションを変更する機能を取り除きます。変更不可能なラッパーには、主に次の2つの用途があります。
コレクションが作成された後でコレクションを不変にすること。この場合、バッキングコレクションへの参照を維持しないことをお勧めします。これは絶対に不変性を保証します。
特定のクライアントにデータ構造への読み取り専用アクセスを許可する。バッキングコレクションへの参照は保持しますが、ラッパーへの参照を渡します。このようにして、完全なアクセスを維持しながら、クライアントは外観を変更することはできません。
(強調鉱山)
これは本当にそれを要約します。
上記のように、変更不可能なコレクションは、たとえば、変更不可能なコレクションに他のオブジェクトによって参照されている基になるデリゲートコレクションがあり、そのオブジェクトによって変更された場合に変更できるため、不変ではありません。
不変に関しては、それも明確に定義されていません。ただし、通常はオブジェクトが「変更されない」ことを意味しますが、再帰的に定義する必要があります。たとえば、インスタンス変数がすべてプリミティブで、メソッドがすべて引数を含まず、プリミティブを返すクラスで不変を定義できます。次に、メソッドは再帰的にインスタンス変数を不変にし、すべてのメソッドに不変で不変の値を返す引数を含めることができます。これらのメソッドは、時間の経過とともに同じ値を返すことが保証されている必要があります。
私たちがそれができると仮定すると、スレッドセーフという概念もあります。そして、不変(または時間の経過とともに変化しない)もスレッドセーフを意味すると信じるようになるかもしれません。 しかし、そうではありませんここで私が述べている主要な点は、他の回答ではまだ言及されていません。常に同じ結果を返すがスレッドセーフではない不変オブジェクトを構築できます。これを確認するには、追加と削除を時間をかけて維持して不変のコレクションを作成するとします。これで、不変コレクションは、内部コレクション(時間の経過とともに変化する可能性があります)を調べ、コレクションの作成後に追加または削除された要素を(内部で)追加および削除することによって、その要素を返します。明らかに、コレクションは常に同じ要素を返しますが、値を変更しないという理由だけではスレッドセーフではありません。
これで、不変をスレッドセーフで変更されないオブジェクトとして定義できます。一般にそのようなクラスにつながる不変クラスを作成するためのガイドラインがありますが、たとえば、上記の「スナップショット」コレクションの例で説明されているように、スレッドの安全性に注意を払う必要がある不変クラスを作成する方法がある場合があることに注意してください。
Java™チュートリアルでは、次のように述べています。
ラップされたコレクションに機能を追加する同期ラッパーとは異なり、変更できないラッパーは機能を奪います。特に、コレクションを変更するすべての操作をインターセプトしてUnsupportedOperationExceptionをスローすることにより、コレクションを変更する機能を取り除きます。変更不可能なラッパーには、主に次の2つの用途があります。
コレクションが作成された後でコレクションを不変にすること。この場合、バッキングコレクションへの参照を維持しないことをお勧めします。これは絶対に不変性を保証します。
特定のクライアントにデータ構造への読み取り専用アクセスを許可する。バッキングコレクションへの参照は保持しますが、ラッパーへの参照を渡します。このようにして、完全なアクセスを維持しながら、クライアントは外観を変更することはできません。
違いを理解するのに十分な説明だと思います。