序文
Java Cloning(クローン)はJava言語の特徴の1つですが、実際に使用することはまれです。しかし、クローニングがより便利で効率的である場合があります。
クローンの場合、Javaにはいくつかの制限があります。
1.クローン化されたクラスは、クローン可能なインターフェイス自体を実装して、 Object.clone()メソッドがフィールドごとにこのクラスのインスタンスを法的にコピーできることを示す必要があります。クローン可能なインターフェイスは、実際には識別インターフェイスであり、インターフェイスメソッドがありません。
2。クローン可能なインターフェイスを実装するクラスは、パブリックメソッドを使用してObject.clone (保護されています)をオーバーライドする必要があります。このインターフェイスを実装した後、オブジェクトがクローンを作成することは不可能です。クローン法が反射的に呼ばれていても、それが成功するという保証はありません。
3. Java.lang.Objectクラスのクローニング方法は、次のように定義されています。
保護されたオブジェクトclone()は、cloneNotsupportedexceptionをスローします
このオブジェクトのコピーを作成して返します。これは、同じパッケージに表示される保護された方法であることを示しています。
慣習により、 super.cloneを呼び出すことにより、返されたオブジェクトを取得する必要があります。
Javaでの割り当て
Javaでは、割り当てが非常に一般的に使用されています。簡単な割り当ては次のとおりです。
//オリジナルタイプint a = 1; int b = a; //参照型文字列[] weekdays = new string [5]; string [] gongzuori = weekdays; //コピーのみ参照のみ
上記のコードで。
1.元のデータ型の場合、割り当てによって渡される値は実際の値です。
2.参照データ型の場合、割り当てはオブジェクトではなくオブジェクトへの参照を渡します。
データ型と参照タイプの違いを理解することで、クローンを理解しやすくなります。
クローン
Javaでは、クローンは、既存のオブジェクトをメモリにコピーするプロセスであり、それと同じ別のオブジェクトになります。 Javaのクローニングは、ドメインごとのコピーです。
Javaでクローンメソッドをサポートしたい場合は、最初にクローン可能なインターフェイスを実装する必要があります
クローン可能は実際には少し奇妙です。これは、よく使用するインターフェイスとは異なります。内部にはメソッドが含まれておらず、単なるマーキングインターフェイスです。
ソースコードは次のとおりです
パブリックインターフェイスクローン可能{}クローン可能について、何に注意すべきか
1.クローンをサポートする場合は、クローン可能なインターフェイスを実装する必要があります
2.クローンメソッドがクローン可能なインターフェイスに呼び出されない場合、クローンノッツサポートエクセプトがスローされます。
次に、クローンメソッドを書き換えて、パブリックアクセスレベルに変更します
静的クラスのクローン可能なインプリは、クローン可能{public int count;パブリックチャイルド。 @Override public object clone()throws clonenotsupportedexception {return super.clone(); }}クローンメソッドを呼び出してオブジェクトをコピーします
cloneableimp Imp1 = new cloneableimp(); imp1.child = new Child( "andy"); try {object obj = imp1.clone(); cloneableimp imp2 =(cloneableimp)obj; System.out.println( "Main Imp2.Child.Name =" + Imp2.Child.Name);} catch(clonenotsuptedexception e){e.printstacktrace();}ライトコピー
上記のコードに実装されているクローンは、実際には浅いコピーです。
浅いコピーについて知っておくべきこと
1.デフォルトのクローンメソッドを使用します
2。元のデータフィールドの値コピーを作成します
3.参照タイプの参照のみをコピーします
4.迅速な実行と高効率
5.データを100%分離することはできません。
6.オブジェクトが元のデータドメインまたは不変のオブジェクトドメインのみを含む場合、浅いコピーを使用することをお勧めします。
分離できないことに関して、このコードを使用して検証できます。
cloneableimp Imp1 = new cloneableimp(); imp1.child = new Child( "andy"); try {object obj = imp1.clone(); cloneableimp imp2 =(cloneableimp)obj; IMP2.CHILD.NAME = "BOB"; System.out.println( "Main Imp1.Child.Name =" + Imp1.Child.Name);} catch(clonenotsupportedexception e){e.printstacktrace();}上記のコードでは、IMP1のクローン方式を使用してIMP2をクローンし、その後imp2.child.nameをBOBに変更し、 imp1.child.nameを印刷して結果を取得しました。
Main Imp1.Child.Name = BOB
その理由は、浅いコピーがデータの100%分離を達成しないためです。 IMP1とIMP2は同じ子オブジェクトを共有するため、1つの変更が他のオブジェクトに影響します。
ディープコピー
ディープコピーは、データの100%分離の問題を解決できます。上記のコードを変更するだけです。
1。子どもがクローン可能なインターフェイスを実装します。
パブリッククラスの子供はクローン可能{public string name; public child(string name){this.name = name; } @Override public String toString(){return "child [name =" + name + "]"; } @Override保護されたオブジェクトclone()throws clonenotsupportedexception {return super.clone(); }}2.クローン法を書き換え、データドメインのクローンメソッドを呼び出します。
静的クラスのクローン可能なインプリは、クローン可能{public int count;パブリックチャイルド。 @Override public Object clone()throws clonenotsuptedexception {cloneableimp obj =(cloneableimp)super.clone(); obj.child =(child)child.clone(); OBJを返します。 }} imp2.child.name再度変更すると、IMP1とIMP2がそれぞれ独自の子オブジェクトを持っているため、 imp1.child.nameの値には影響しません。データは100%分離されているためです。
ディープコピーのいくつかの機能
1.親クラスメソッドを呼び出すだけでなく、属性のクローンメソッドを呼び出すことも、クローンメソッドをオーバーライドする必要があります。
2。元のオブジェクトとクローンオブジェクトの間の100%のデータ分離が達成されます
3.オブジェクトに参照型属性がある場合、ディープコピーを使用することをお勧めします。
4.ディープコピーは、浅いコピーよりも時間がかかり、効率が低い
クローニングを使用する理由
それは非常に重要で一般的です。APIはリストコレクションを提供する必要がありますが、発信者の変更が独自の変更に影響を与えることを望んでいないため、データ分離の目的を達成するにはオブジェクトをクローンする必要があります。
クルーンはできるだけ避けるべきです
1.通常、インターフェイスは、クラスが顧客に何ができるかを示すために実装されますが、クローン可能は単なるタグインターフェイスであり、スーパークラスで手で保護されたメソッドの動作も変更します。インターフェイスの非常に非定型的な使用法であり、模倣に値しません。
2.クローンメソッド慣習とその脆弱なクローン法のJavadocの説明は、次のように少し曖昧です:Java SE8条約
クローンメソッドは、オブジェクトのコピーを作成して返します。コピーの正確な意味は、オブジェクトのクラスによって異なります。一般的な意味は、任意のオブジェクトxの場合、式は
x.clone() != x 为true x.clone().getClass() == x.getClass()もtrueを返しますが、必須ではありませんがx.clone().equals(x)
上記の2番目と3番目の式は、簡単にFalseを簡単に返します。したがって、永続的な真のものを保証できる唯一のものは式1つです。つまり、2つのオブジェクトは独立したオブジェクトです。
3.変数オブジェクトの最終ドメイン。クローニング方法では、変数オブジェクトの最終ドメインをコピーする必要がある場合、最終的な制限のためにコンパイルして合格することは実際には不可能です。したがって、クローニングを実装するには、可変オブジェクトドメインの最終キーワードを放棄することを検討する必要があります。
4.スレッドの安全スレッドセーフクラスを使用してクローン可能なインターフェイスを実装する場合は、クローンメソッドが同期していることを確認する必要があります。デフォルトのObject.cloneメソッドは同期されていません。
一般に、Javaのクローン法は実際には完璧ではないため、可能な限り使用しないようにすることをお勧めします。ここにいくつかの選択肢があります。
コンストラクターをコピーします
コピーオブジェクトは、コピーコンストラクターを使用して実装することもできます。
1。コピーコンストラクターは、コンストラクターの一種でもあります
2. 1つのパラメーターのみが受け入れられます。パラメータータイプは現在のクラスです
3。目的は、同じパラメーターを持つ新しいオブジェクトを生成することです
4.クローン法よりもコピーコンストラクターの利点は、シンプルで簡単に実装できることです。
コピーコンストラクターを使用したサンプルコード
パブリッククラスカー{ホイールホイール;文字列メーカー。パブリックカー(ホイールホイール、ストリングメーカー){this.wheel = wheel; this.manufacturer = Manufacturer; } //コンストラクターパブリックカー(カーカー){this(car.wheel、car.Manufacturer); } public static class wheel {string brand; }}上記のコードは浅いコピーとして実装されていることに注意してください。ディープコピーを実装する場合は、次のコードを参照してください。
// ConstructOrpublic Car(Car Car){wheel wheel = new Wheel(); wheel.brand = car.wheel.brand; this.wheel = wheel; this.manufacturer = car.Manufacturer;}より便利なため、上記のクラスに静的方法を追加することもできます
public static car newinstance(car car){return new car(car);}Serializableを使用して、深いコピーを実現します
実際、オブジェクトの深いコピーは、シリアル化を使用して達成できます。簡単なコードは次のとおりです
Public Class DeepCopyexampleはSerializable {private static final long serialversionuid = 6098694917984051357l;パブリックチャイルド。 public deepcopyexample copy(){deepcopyexample copy = null; try {bytearrayoutputStream baos = new bytearrayoutputStream(); ObjectOutputStream OOS = new objectOutputStream(baos); oos.writeobject(this); bytearrayinputStream bais = new bytearrayinputStream(baos.tobytearray()); ObjectInputStream ois = new ObjectInputStream(BAIS); copy =(deepcopyexample)ois.readobject(); } catch(ioexception e){e.printstacktrace(); } catch(classNotFoundException e){e.printstacktrace(); }コピーを返します。 }}その中で、子供はシリアル化可能なインターフェイスを実装する必要があります
パブリッククラスの子供はシリアル化可能{private static final long serialversionuid = 6832122780722711261L; public string name = ""; public child(string name){this.name = name; } @Override public String toString(){return "child [name =" + name + "]"; }}例とテストコードを使用します
deepcopyexample example = new deepcopyexample(); example.child = new Child( "Example"); deepcopyexample copy = example.copy(); if(copy!= null){copy.child.name = "copied"; System.out.println( "example.child =" + example.child + "; copy.child =" + copy.child);} //出力結果:example.child = child [name = example]; copy.child = child = copied]出力結果から判断すると、コピーオブジェクトの子価値を変更しても、オブジェクトの例、つまりシリアル化を使用してオブジェクトの深いコピーを実現することには影響しません。
要約します
上記は、Javaのクローニングのすべての内容です。この記事がJavaを学ぶのに役立つことを願っています。