web-dev-qa-db-ja.com

Collections.unmodifiableListおよび防御コピー

書いたら

List<Integer> a1 = Arrays.asList(1, 2, 3);
List<Integer> a2 = Collections.unmodifiableList(a1);

a2は読み取り専用ですが、書き込む場合

a1.set(0,10);

a2も変更されます。

APIの場合:

指定されたコレクションの変更不可能なビューを返します。このメソッドにより、モジュールはユーザーに内部コレクションへの「読み取り専用」アクセスを提供できます。

次に、元のコレクションを変更すると、ターゲットコピーされたコレクションも変更されるのはなぜですか?

たぶん私はその意味を誤解したのでしょうか、もしそうならそのコレクションの防御的なコピーを書く方法は何ですか?

41
xdevel2000

はい、あなたはそれを正しく理解しました。アイデアは、umodifiableCollectionによって返されるオブジェクトを直接変更することはできませんが、他の方法で変更することができるということです(内部コレクションを直接変更することにより効果的に)。

何かが内部リストにアクセスできる限り、「変更できない」コレクションは変更できます。

そのため、通常は変更不可能なコレクションを作成し、内部リストに何もアクセスできないようにします。

Collection<Integer> myUmodifiableCollection = Collection.umodifiableCollection(Arrays.asList(1, 2, 3));

Listによって作成されたasListへの参照を取得するものはないため、これは本当に変更不可能なコレクションです。

このアプローチの利点は、元のコレクション/リストをまったくコピーする必要がないことです。これにより、メモリと計算能力の使用が回避されます。

Guava は、真の不変コレクションを提供する ImmutableCollection クラス(および ImmutableList などのサブクラス)を提供します(通常、ソースをコピーします)。

49
Joachim Sauer

たぶん私はその意味を誤解したのでしょうか、もしそうならそのコレクションの防御的なコピーを書く方法は何ですか?

通常、次のように使用します。

private List<Integer> a1 = Arrays.asList(1, 2, 3);

public List<Integer> getUnmodifiable() {
    return Collections.unmodifiableList(a1);
}

getUnmodifiableandを呼び出す人は、クラスの内部にアクセスできません(つまり、プライベート変数a1にアクセスできません)、できません返されたリストを変更します。

10
assylias

ステートメント:

Collections.unmodifiableList(a1);

修飾子メソッドがUnsupportedOperationExceptionをスローする元のコレクションのラッパーを返します。

ラッパーはリードスルーです。つまり、a1、変更はラップされたコレクションに反映されますa2

1

a1可変で、グアバなしで不変のコピーを作成します。これはあなたがそれを行うことができる1つの方法です。

    List<Integer> a1 = Arrays.asList(1, 2, 3);
    List<Integer> a2 = Collections.unmodifiableList(new ArrayList<>(a1));
1
Travis Miller

a2を使用してリストを変更することはできません。

a1リストを変更すると、実際にa2に表示されるものが変更されます-これは意図したものです。

リストa1にアクセスするための公開された方法を持ってはいけません。

1
vikingsteve

aPIはそれを言う内部コレクションあなたの場合、コレクションは内部ではない

ポイントは、クラスにプライベートリストがあり、そのリストのgettetである場合、ゲッターの呼び出し元が、変更できないリストを返す必要がある場合にリストを変更できないようにすることです。それ以外の場合、返されるリストは内部/プライベートリストへの単なる参照であるため、コンテンツを変更できます。

1
A4L

変更不可能で不変のリスト、つまり他のライブラリに依存しないソースリストの変更不可能なコピーが必要な場合は、これを試してください。

_Collections.unmodifiableList(Collections.list(Collections.enumeration(sourceList)))
_

Collections.list()は、列挙から値をコピーします。

0
UR6LAD