7

List要素を削除または追加できない が必要です。Java 8 のCollections.unmodifiableListで答え​​を見つけたと思いました。元のリストを渡すと、おそらく変更不可能なリストが返されます。

しかし、元のリストから要素を削除すると、変更不可能なリストが変更されます。何が起こっている?

このデモ コードを参照してください。オリジナルから削除すると、変更不可能なリストが 3 つの要素 2 から縮小されます。

String dog = "dog";
String cat = "cat";
String bird = "bird";

List< String > originalList = new ArrayList<>( 3 );
originalList.add( dog );
originalList.add( cat );
originalList.add( bird );

List< String > unmodList = Collections.unmodifiableList( originalList );
System.out.println( "unmod before: " + unmodList );  // Yields [dog, cat, bird]
originalList.remove( cat );  // Removing element from original list affects the unmodifiable list?
System.out.println( "unmod after: " + unmodList );  // Yields [dog, bird]
4

1 に答える 1

8

unmodifiableList は元のリストに裏打ちされています

ユーティリティ クラスのそのunmodifiableListメソッドはCollections、新しいリストを作成しません。元のリストに基づく疑似リスト作成します。「変更不可能な」オブジェクトを介して行われる追加または削除の試みはブロックされるため、名前はその目的を果たします。しかし、確かに、あなたが示したように、元のリストは変更可能であり、同時に、完全に変更不可能な二次リストに影響を与えます。

これは、クラスのドキュメントに記載されています。

指定されたリストの変更不可能なビューを返します。この方法により、モジュールはユーザーに内部リストへの「読み取り専用」アクセスを提供できます。返されたリストに対するクエリ操作は、指定されたリストを「読み取り」、直接または反復子を介して返されたリストを変更しようとすると、UnsupportedOperationException が発生します。

その 4 番目の単語が鍵ですview。新しいリスト オブジェクトは新しいリストではありません。オーバーレイです。図面の上にトレーシング ペーパー透明フィルムを貼ると、図面にマークを付けることができなくなるのと同じように、元の図面を修正するために下に移動することを防止することはできません。

教訓: Collections.unmodifiableList を使用して、リストの防御的なコピーを作成しないでください。

Collections.unmodifiableMap、などについても同様Collections.unmodifiableSetです。

グーグルグアバ

クラスの代わりに、Collections防御的プログラミングのために、Google GuavaライブラリとそのImmutableCollections機能を使用することをお勧めします。

新しいリストを作成できます。

public static final ImmutableList<String> ANIMALS = ImmutableList.of(
        dog,
        cat,
        bird );

または、既存のリストの防御的なコピーを作成することもできます。この場合、新しい別のリストを取得します。元のリストから削除しても、不変リストには影響しません (縮小されます)

ImmutableList<String> ANIMALS = ImmutableList.copyOf( originalList ); // defensive copy!

ただし、コレクション自体の定義は分離されていますが、含まれているオブジェクトは元のリストと新しい不変リストの両方で共有されていることに注意してください。その防御コピーを作成するとき、「犬」オブジェクトを複製していません。1 つの犬オブジェクトだけがメモリに残り、両方のリストに同じ犬を指す参照が含まれます。「犬」オブジェクトのプロパティが変更された場合、両方のコレクションが同じ単一の犬オブジェクトを指しているため、両方のコレクションが犬の新しいプロパティ値を参照します。

于 2015-09-02T20:41:59.147 に答える