4

clone()にメソッドを実装しようとしていDoubleLinkedListます。DoubleLinkedListさて、問題は、「規則」によってそれを実装することは、単に新しいものを作成して、現在のDoubleLinkedListのすべての要素で埋めるよりもはるかに面倒なことです。

それをしているときに私が見ない不便はありますか?

これが私の現在のアプローチです:

@Override
public DoubleLinkedList<T> clone() {
    DoubleLinkedList<T> dll = new DoubleLinkedList<T>();

    for (T element : dll) {
        dll.add(element);
    }

    return dll;
}

慣例により、次のようになります。

@Override
public DoubleLinkedList<T> clone() {
    try {
        DoubleLinkedList<T> dll = (DoubleLinkedList<T>)super.clone();
        //kinda complex code to copy elements
        return dll;
    } catch (CloneNotSupportedException e) {
        throw new InternalError(e.toString());
    }
}
4

4 に答える 4

5

あなたが正しく指摘しているように、慣例は常にsuper.clone()の実装の最初に呼び出すことですclone()。上のAPIドキュメントからObject#clone()

慣例により、返されるオブジェクトはsuper.cloneを呼び出すことによって取得する必要があります。クラスとそのすべてのスーパークラス(オブジェクトを除く)がこの規則に従う場合、x.clone()。getClass()== x.getClass()の場合になります。

(を使用せずに)最初に試行するとsuper.clone()、次の問題が発生します。

私が持っているとしましょう

class IntDoubleLinkedList extends DoubleLinkedList<Integer> implements Cloneable

(そしてそれIntDoubleLinkedListはオーバーライドすることを気にしませんclone())そして私は次のコードを実行します:

IntDoubleLinkedList idll = new IntDoubleLinkedList();
IntDoubleLinkedList idll2 = (IntDoubleLinkedList) idll.clone();

何が起こるか?のcloneメソッドが実行されます DoubleLinkedList。このメソッドは、super.clone()を経由しない場合、インスタンスを返します。このインスタンスは、DoubleLinkedListにキャストできませんIntDoubleLinkedListAClassCastExceptionがスローされます!

super.clone()では、この問題をどのように解決しますか?さて、誰もがsuper.clone()オーバーライドされたクローンメソッドを呼び出すという規則に固執するObject.clone()と、最終的に呼び出され、この実装は適切なタイプのインスタンス(IntDoubleLinkedListこの場合)を作成します!

于 2010-06-03T11:47:14.000 に答える
1

他の人が説明しているように、あなたがオーバーライドしようとしているなら、あなたはcloneその契約に従うべきです。

現在の方法が気に入った場合は、実装をコピーコンストラクターまたは静的ファクトリメソッドに変換しDoubleLinkedListないでください。Cloneable静的ファクトリメソッドには、ジェネリック型引数に型推論を少し提供するという追加の利点もあります。

PS二重リンクリストです。LinkedList

于 2010-06-03T11:54:50.557 に答える
0

新しいリストを作成し、ソースからすべての要素を追加してそれを行う場合、次のようなことを行います。

DoubleLinkedList<Foo> l1 = new DoubleLinkedList<Foo>();
l1.add (new Foo(params));
DoubleLinkedList<Foo> l2 = l1.clone();
Foo foo = l2.get(0);
foo.setProperty("new Value");

foo.propertyは、両方のリストで「新しい値」になります(逆の場合も同じです。l1で変更すると、変更はl2に表示されます)。正しい方法は、実際にすべての要素のクローンを作成し、クローンを追加してリストが独立していることを確認することです。これは、要素のプロパティを変更した場合にのみ発生し、リストから要素を追加、移動、削除した場合には発生しないことに注意してください。

編集:リンクリストであるため、次/前の要素は要素のプロパティであり、追加、削除しても両方のリストに影響することに気づきました。

于 2010-06-03T11:34:32.800 に答える
0

「規則」を呼び出す理由はsuper.clone()、複製されたオブジェクトの最終的なタイプが複製されているオブジェクトと一致することを確認するためです。たとえばDoubleLinkedListclone()メソッドで独自のnewをインスタンス化する場合、今のところは問題ありませんが、後でサブクラスがオーバーライドに失敗すると、独自のクラスでclone()はなくクローンが返されます。DoubleLinkedList(追加のフィールドがある場合は、クローンを作成することもできません。おそらく、より大きな問題があります。)

その意味で、従来の方法が好まれ、確かに不格好です。

ただし、どちらの実装にも同様の問題があります。データ構造をディープコピーしていないということです。クローンは浅い警官にすぎません。これはおそらく、発信者が期待するものではありません。を調べて、の各値を値のクローンに置き換える必要がありDoubleLinkedListます。他の非プリミティブフィールドについても同様です。

その意味で、従来の方法ではここで間違った結果が得られます!あなたは第三の道が必要です。element.clone()たとえば追加する必要があることを除いて、最初の方法はおそらくほぼ機能します。

于 2010-06-03T11:49:55.103 に答える