1

私はこのようにコード化された防御的なコピーを見てきました

void someMethod(Date d) {
    myDate = new Date( d.getTime() );
}

しかし、それは私には意味がありません。Javaで、そのオブジェクトのメモリに同一のコピーを作成する方法はありませんか?

すべての場合に機能するとは限らないことを読みましたclone()が、その理由はわかりません。

4

4 に答える 4

7

これに答えようとすることもできますが、Josh Bloch を盗用しているだけなので、代わりにリソースへのリンクを次に示します。

コピー コンストラクターとクローン作成

Bill Venners: あなたの著書では、実装Cloneableして記述する代わりにコピー コンストラクターを使用することを推奨していますclone。それについて詳しく説明していただけますか?

Josh Bloch:私の本でクローンに関する項目を読んだことがあるなら、特に行間を読んだことがあれば、クローンが深く壊れていると私が考えていることがわかるでしょう。いくつかの設計上の欠陥がありますが、その最大のものは、Cloneableインターフェイスにメソッドがないことcloneです。そして、それは単にうまくいかないことを意味します。何かを作ることは、それでCloneable何ができるかについて何も言いません. 代わりに、内部で何ができるかについて何かを述べています。super.clone繰り返し呼び出してObjectのメソッドを呼び出すことになった場合clone、このメソッドは元のフィールドのコピーを返す、ということです。

しかし、インターフェイスを実装するオブジェクトで何ができるかについては何も述べていません。つまり、多態的な操作Cloneableを行うことはできません。cloneの配列がある場合Cloneable、その配列を実行し、すべての要素を複製して配列のディープ コピーを作成できると思うかもしれませんが、それはできません。には publicメソッドがなく、 にもないため、何かをキャストしてメソッドCloneableを呼び出すことはできません。メソッドにキャストして呼び出そうとすると、コンパイラは、オブジェクトの保護されたメソッドを呼び出そうとしていると言います。cloneCloneablecloneObjectCloneablecloneclone

問題の真実は、コピー機能以外のCloneableパブリックメソッドを実装および提供することによって、クライアントに機能を提供していないということです。cloneこれは、別の名前でコピー操作を提供し、実装しない場合に得られるものよりも優れていますCloneable。これは基本的に、コピー コンストラクターで行っていることです。コピー コンストラクターのアプローチにはいくつかの利点があり、それについては本で説明しています。大きな利点の 1 つは、オリジナルとは異なる表現を持つようにコピーを作成できることです。たとえば、 を にコピーできLinkedListますArrayList

Objectclone方法は非常にトリッキーです。これはフィールド コピーに基づいており、「言語外」です。コンストラクターを呼び出さずにオブジェクトを作成します。コンストラクターによって確立された不変条件が保持されるという保証はありません。super.cloneオブジェクトのクローンを作成するまでチェーンを繰り返し呼び出すと、オブジェクトの浅いコピーが作成されるという事実に起因して、Sun の内外で長年にわたって多くのバグが発生しています。クローンは通常、クローンされるオブジェクトと状態を共有します。その状態が変更可能な場合、2 つの独立したオブジェクトはありません。一方を変更すると、他方も変更されます。そして突然、ランダムな動作になります。

もう使っているものはほとんどありCloneableません。clone人々がそれを期待しているので、私はよく具象クラスに public メソッドを提供します。抽象クラスを実装したり、インターフェイスを拡張したりしません。これは、抽象クラス (またはインターフェイス) を拡張 (または実装) するすべてのクラスCloneableに実装の負担をかけないためです。Cloneableそれは本当に負担であり、メリットはほとんどありません。

Doug Lea はさらに先へ進みます。clone彼は、配列をコピーする以外にはもう使っていないと私に言いました。を使用cloneして配列をコピーする必要があります。これが一般的に最速の方法だからです。しかし、Doug の型はCloneableもはや実装されていません。彼はそれをあきらめました。そして、それは不合理ではないと思います。

Cloneable壊れているのは残念ですが、起こります。オリジナルの Java API は、市場のクロージング ウィンドウに間に合うように、厳しい締め切りの中で非常に迅速に作成されました。オリジナルの Java チームは素晴らしい仕事をしましたが、すべての API が完璧というわけではありません。Cloneableは弱点であり、人々はその限界を認識する必要があると思います。

于 2010-02-10T04:48:26.260 に答える
3

clone()JVMまたはコンパイラが作成しない複製に関連する多くの決定があるため(たとえば、浅いコピーと深いコピー)、一部のクラスでのみ意味のある実装が行われます。また、Java の概念全体が壊れているため、めったに使用されないと主張する人もいます。

ただし、最終的には、多くのクラスを複製できません。このような場合、ユーザーは、1 つのオブジェクトを別のオブジェクトに基づいて生成および初期化することにより、それらのクローンを作成します。

ただし、Dateクラスは を実装Cloneableしているため、「コピー コンストラクター」を使用する場合と比較して、この特定のケースでは実際にはメリットがありません。

複製が望ましい状況の 1 つは、クラス階層を操作している場合です。最も外側の式を参照する Expression サブタイプのツリーとして数式を表現していると想像してください。

この場合はプラスだとしましょう。Expression への参照で clone を呼び出しますが、実際に得られるのは Plus の新しいインスタンスです。Expression はインターフェイスまたは抽象クラスになる可能性があるため、コンストラクターでは実際にはそれを行うことはできません。

于 2010-02-10T04:50:57.380 に答える
1

常に機能する同一のコピーを作成する簡単な方法はありません。

クローンはそれを行うことになっていましたが、すべてのクラスで実装されているわけではないため、多かれ少なかれ壊れています。

別のアプローチは、シリアル化/逆シリアル化することですが、シリアル化もすべてのクラスでサポートされているわけではありません。

于 2010-02-10T04:49:18.510 に答える
0

モバイルコードのセキュリティの観点から、clone通常はオーバーライドできます。

@Override public Date clone() {
    return this; // Ha!
}

セキュリティを気にしない場合でも、プログラマーが「賢く」コードにバグレポートを作成していることを想像できます。

clone特にまったく同じランタイムタイプを返すという期待も、実装上の問題を引き起こします。

于 2010-02-10T10:05:49.330 に答える