質問

Javaについて説明するいくつかのチュートリアルを探していました Cloneable, 、しかし、良いリンクを取得しておらず、スタックオーバーフローはとにかくより明白な選択になりつつあります。

以下を知りたい:

  1. Cloneable を実装することにより、オブジェクトのクローンまたはコピーを持つことができることを意味します Cloneable インターフェース。それを行うことの利点と欠点は何ですか?
  2. オブジェクトが複合オブジェクトである場合、再帰的なクローニングはどのように発生しますか?
役に立ちましたか?

解決

最初に知っておくべきこと Cloneable IS-使用しないでください。

クローニングを実装するのは非常に困難です Cloneable 正しい、そして努力はそれだけの価値がない。

その代わりに、Apache-Commonsのような他のオプションを使用します SerializationUtils (ディープクローン)または BeanUtils (浅いクローン)、または単にコピーコンストラクタを使用します。

こちらをご覧ください クローニングについてのジョシュ・ブロッホの眺めのために Cloneable, 、アプローチの多くの欠点を説明しています。 (ジョシュア・ブロッホ 太陽の従業員であり、多くのJava機能の開発を主導しました。)

他のヒント

クローン可能自体は、残念ながら、単なるマーカーインターフェイスです。つまり、clone()メソッドを定義しません。

そうであることは、保護されたオブジェクトの動作を変更することです。Clone()メソッドは、クローン可能な実装しないクラスのクロノトサポートエクセプトをスローし、行うクラスに対してメンバーごとの浅いコピーを実行します。

これがあなたが探している動作であっても、それを公開するために独自のclone()メソッドを実装する必要があります。

独自のclone()を実装する場合、アイデアは、正しいクラスであることが保証されているSuper.clone()によって作成されるオブジェクトから開始することであり、浅いコピーの場合に追加のフィールド集団を実行することです。あなたが欲しい。サブクラスが独自のクローン可能なロジックを追加する必要がある場合に、Clone()からコンストラクターを呼び出すことは問題があります。この場合、super.clone()を呼び出すと、間違ったクラスのオブジェクトが取得されます。

このアプローチは、コンストラクターで定義される可能性のあるロジックをバイパスします。これは、問題が発生する可能性があります。

別の問題は、Clone()をオーバーライドするのを忘れているサブクラスがデフォルトの浅いコピーを自動的に継承することです。これは、可変状態の場合に必要なものではない可能性があります(ソースとコピーの間で共有されるようになります)。

ほとんどの開発者は、これらの理由でクローン可能を使用しておらず、代わりにコピーコンストラクターを実装するだけです。

クローン可能の詳細と潜在的な落とし穴については、Joshua BlochのEfferecment Javaという本を強くお勧めします

  1. クローニングは、コンストラクターなしで、オブジェクトを構築するための特別な言語的方法を呼び出します。
  2. クローニングでは、CloneNotsuptedExceptionで何らかの形で治療する必要があります。
  3. 利点は小さいです - コピーコンストラクターを手動で書く必要はありません。

したがって、慎重にクローン可能を使用してください。それはあなたがすべてを正しく行うために適用するために必要な努力と比較してあなたに十分な利益を与えません。

クローニングは基本的なプログラミングパラダイムです。 Javaが多くの点でそれを貧弱に実装した可能性があるという事実は、クローニングの必要性をまったく減少させません。そして、あなたがそれを機能させたいと思うように、動作するクローニングを実装するのは簡単です。関数に名前クローンを使用して、必要に応じてクローン可能を実装しないこともできます。

このようなタイプAのオブジェクトのリストがある場合、BとCがAから派生しているクラスA、B、およびCがあると仮定します。

ArrayList<A> list1;

これで、そのリストには、タイプA、B、またはCのオブジェクトが含まれます。オブジェクトがどんなタイプであるかはわかりません。したがって、このようなリストをコピーすることはできません。

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(new A(a));
}

オブジェクトが実際にタイプBまたはCの場合、正しいコピーを取得しません。そして、Aが抽象的である場合はどうなりますか?今、何人かの人々がこれを提案しています:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    if(a instanceof A) {
        list2.add(new A(a));
    } else if(a instanceof B) {
        list2.add(new B(a));
    } else if(a instanceof C) {
        list2.add(new C(a));
    }
}

これは非常に悪い考えです。新しい派生タイプを追加した場合はどうなりますか? BまたはCが別のパッケージに入っていて、このクラスでそれらにアクセスできない場合はどうなりますか?

あなたがしたいのはこれです:

ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
    list2.add(a.clone());
}

多くの人々が、クローンの基本的なJava実装に問題がある理由を示しています。しかし、それはこのように簡単に克服されます:

クラスAで:

public A clone() {
    return new A(this);
}

クラスBで:

@Override
public B clone() {
    return new B(this);
}

クラスCで:

@Override
public C clone() {
    return new C(this):
}

同じ関数名を使用するだけで、クローン可能な実装ではありません。あなたがそれが好きではないなら、それに何か他のものに名前を付けてください。

a)コピーコンストラクターよりもクローンの利点はあまりありません。おそらく最大のものは、まったく同じ動的タイプの新しいオブジェクトを作成する機能です(宣言されたタイプがクローン可能であり、パブリッククローン法を持っていると仮定します)。

b)デフォルトのクローンは浅いコピーを作成し、クローンの実装が変更されない限り、浅いコピーのままになります。特にクラスが最終フィールドを持っている場合、これは難しい場合があります

Bozhoは正しいです、クローンは正しくなるのが難しい場合があります。コピーコンストラクター/工場がほとんどのニーズに対応します。

クローン可能な不利な点は何ですか?

クローンが浅いコピーを作成するため、コピーしているオブジェクトに構成がある場合、クローニングは非常に危険です。

DB関連の操作を処理するオブジェクトが1つあるとしましょう。そのオブジェクトは持っています Connection プロパティの1つとしてオブジェクト。

誰かがクローンを作成するとき originalObject, 、作成されているオブジェクト、たとえば、 cloneObject。ここに originalObjectcloneObject 同じ参照を保持します Connection 物体。

言っておいてください originalObject 閉じます Connection オブジェクト、だから今 cloneObject なぜなら connection オブジェクトはそれらの間で共有され、それは実際に閉じられました originalObject.

IOSTREAMをプロパティとしてクローン化することを確認する場合、同様の問題が発生する可能性があります。

オブジェクトが複合オブジェクトである場合、再帰的なクローニングはどのように発生しますか?

クローン可能は浅いコピーを実行します。意味は、元のオブジェクトとクローンオブジェクトのデータが同じ参照/メモリを指していることです。ディープコピーの場合は、元のオブジェクトのメモリからのデータがクローンオブジェクトのメモリにコピーされます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top