3

以下のような構造の不変クラスを実装していました。

public final class A{
    private final B bOb;
    public A(){
        bOb = new B();
    }
    public A(A a){
        bOb = new B(a.bOb);
    }
    public A addData(Type data){ // Type - Integer,String,char,etc.
        A newA = new A(this); //making a copy of the object that is calling addData method
        newA.bOb.add(data);
        return newA;
    }
}

この実装は正しいですか? オブジェクト bOb がリストであるとしましょう。

4

5 に答える 5

2

あなたの実装:

public A addData(int data){
    A newA = new A(this);
    newA.bOb.add(data); // <--- bOb is mutable
    return newA;
}

bOb は変更されているため、bOb への直接アクセスを公開すると変更される可能性があります。(bOb については何も公開していないため、このシナリオは意味がありません。)

ヒント:

  • Collections.emptyList()不変リストを返します。
  • Collections.unmodifiableList()指定されたリストの不変の浅いコピーを返します。

この「より安全な」実装を検討してください。

import java.util.*;

public final class A<T>{ //T must also be immutable (String, integer, char, ...)
    private final List<T> list;
    public A(){
        this.list = Collections.emptyList();
    }
    public A(List<T> list){
        this.list = Collections.unmodifiableList(list);
    }
    public A<T> addData(T data){
        List<T> shallowCopy = new ArrayList<T>(this.list);
        shallowCopy.add(data);
        return new A<T>(shallowCopy);
    }
    public List<T> getItems() {
        return this.list;
    }
}
于 2012-08-23T09:48:48.243 に答える
2

B 自体が (add メソッドを介して) 可変であるように見え、A には B のインスタンスが含まれているため、完全に不変というわけではありません。

ただし、次のすべてが当てはまる場合、事実上不変であると思います(つまり、外部のオブザーバーの観点からは不変であるかのように動作します)。

  • new B(B)の完全なディープ コピーを実行しますB(そうでない場合はaddData、オリジナル内の何かを変更する可能性がありますB)
  • bOb他の手段で参照を漏らしていない
  • 追加された要素自体は不変です

不変であることの利点のほとんどは、事実上不変であることから得られるので、この設計はType不変であれば問題ないと思います。他の誰かへの参照を渡した後にオブジェクトが決して変更されない限り、オブジェクトを構築中に変更しても問題ありません。これの良い例は、java.lang.String内部的には String が構築されている間に書き込まれる可変配列を含みますが、それ以降は変更されません。

于 2012-08-23T09:49:35.080 に答える
1

bObがリストであり、変更可能なコンテンツが含まれている場合は、そうではありません。しかしint、コンテンツとしてのみ使用しているようで、これで問題は解決します。

于 2012-08-23T09:47:05.990 に答える
1

この形式では、はい、クラスは不変です。

ただし、これは些細な例であり、内部データにアクセスできないため、実際には何の役にも立ちません。注意する必要があるのは、bObから参照を逃がさないことAです。を返すメソッドを追加する場合は、呼び出し元が誤って の内容を変更することを避けるために、 のコピーbOb返す必要があります。bObA

于 2012-08-23T09:47:42.933 に答える
0

B(B b)コンストラクターの動作に依存します。コピー コンストラクターの場合は、bフィールドのディープ コピーを作成する必要があります。この場合Aは不変です。

代わりに、コンストラクターが単に同じインスタンスへの参照を取得する場合、その変更はプロパティにb反映されるため、クラスは不変ではありません...bObA

于 2012-08-23T10:22:31.467 に答える