Javaのシャローコピーとディープコピーの詳細なメカニズム-から- https://www.jb51.net/article/106088.htm
概要:
Javaでは、コピーが深いと浅いコピーコピーの2種類に分かれています。Javaは、共通のスーパークラスObject内のcloneと呼ばれる方法で、新しいオブジェクトの浅いコピーのうちクローンのこのメソッドを実装し、そのクローン法でディープコピーとして定義されます。
(A)クローン方法のオブジェクト
我々が参照するために、別のステートメントでのステートメントの前に、後でそれを参照するステートメントを使用して新しいオブジェクトを、新しい場合は、最終的な結果は次のとおりです。同じオブジェクトを指します宣言したこれら2つの変数は、変更がすべてですこれは、変更されました。我々は、オブジェクトのコピーを作成したい場合は、コピーは、同一のさまざまなプロパティやオブジェクトをされて、コピーを変更し、元のオブジェクトは何の関係はありませんので、この時、私たちは、cloneメソッドを使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package
Clone;
import
java.util.Date;
/**
*
* @author QuinnNorris
* java中的两种拷贝机制
*/
public
class
Clone {
/**
* @param args
* @throws CloneNotSupportedException
*/
public
static
void
main(String[] args)
throws
CloneNotSupportedException {
// TODO Auto-generated method stub
ClassA valA =
new
ClassA(
1
,
"old"
,
new
Date());
// 声明一个新的ClassA对象,我们不需要太关注ClassA的功能
ClassA valB = valA;
// 将valA引用的对象赋给valB
valA.setObject(
"new"
);
// 更改valA中的值,此时valB也被更改了,因为valA和valB指向同一个对象
valB = valA.clone();
//通过clone方法制造副本
}
}
|
cloneメソッドに一部を書き換えるにClassAクラス:
1
2
3
4
5
6
7
8
|
//需要实现Cloneable接口
public
class
ClassA
implements
Cloneable {
public
ClassA clone()
throws
CloneNotSupportedException {
return
(ClassA)
super
.clone();
//调用父类(Object)的clone方法
}
}
|
1.オブジェクトのcloneメソッドを使用する方法
それは、我々はそれを共有し、cloneメソッドを使用して、4つのルールを締結しました。
- オブジェクトのコピーを得るために、私たちは、クラスObjectのクローン()メソッドを使用することができます。
- クローンは、派生クラスのベースクラス()メソッドをカバーし、パブリックとして宣言します。
- 派生クラスのclone()メソッドでは、super.clone()を呼び出します。
- 派生クラスでのCloneableインタフェースを実装します。
2.protected修正cloneメソッド
java.lang.Objectのでは、彼はこれは非常に特殊なケースで、この方法は、保護された変更に設定されているクローンを作成します。範囲が保護されて可視+パケット継承。オブジェクトを返すためにこのメソッドがクローン化されているので、将来の世代だけで自然に達成できること、それはそれを書き換えるので、この設定の理由は、タイプが不明であるクローンしようとしているcloneメソッドは、戻り値の型を判別する方法はありません、不当とオープンせずに継承するために、将来の世代を有効にするために、保護されたタイプに設定。
3. Cloneableインタフェースを実装する必要があるcloneメソッドを実装
私たちは、cloneメソッドをオーバーライドしたときに、なぜCloneableインタフェースにそれを達成するために行きますか?実際には、CloneableインタフェースがでJavaでマーカーインタフェース、インタフェースはそれらのないマーキングはメソッドとプロパティのインターフェース、彼らは誰もが情報のいくつかのことを知っているように存在して XXX:、だけでなく、とのinstanceofはあなたが判断できるのCloneableを。これは、Cloneableインタフェースが表示されている設計者は、クローニング・プロセスを知っているように。あなたがオブジェクトを複製、しかし、実装されていないする必要がある場合Cloneableインタフェース(実際には、「書き込み」と「実現」は、より正確である)の異常チェックを生成します。
4.実装cloneメソッドは、親クラスのクローンを呼び出す必要があります
我々は、オブジェクトのまったく同じコピーを達成し、このオブジェクトのメソッドを呼び出すことを目指し、私たちは親クラスのcloneメソッドを使用する必要があり、そのためにも、親クラス、オブジェクトのcloneメソッドに達し知って、[オブジェクトのcloneメソッドは、どのような使用それであります?APIは、これは言うことです。
保護されたオブジェクトのクローンは、()CloneNotSupportedExceptionがスローされます
。このオブジェクトのコピーを作成して返します。
「コピー」オブジェクトのクラスの正確な意味に依存してもよいです。この目的は、任意のオブジェクトx、のためのものである
式:x.clone()は、xが真= ,!
式:. X.clone()のgetClass() == x.getClass()が成立でも同様で、
これらの要件を満たすために持っていません。
通常の状況下で:
。X.clone()のequals(X-)が真であるが、要件を満たすために必要はありません。
慣例により、返されたオブジェクトは、super.cloneを呼び出すことによって取得する必要があります。
クラスと(オブジェクトを除く)、そのすべてのスーパークラスは、本契約に準拠する必要がある場合、x.clone()。のGetClass()== x.getClass()が成立します。
APIは、上記のクローンの一部の基本的な説明です。私たちは、それは、オブジェクトが複製されるように戻ります()合理的なコールspuer.clone限り、それを締結することができます。実行時には、クローン()のオブジェクトは、元のオブジェクトの新しいオブジェクトのコピースペースに一つ一つの内容をオブジェクトを使用すると、オブジェクト、この目的のために割り当てられた後、オブジェクト空間をコピーしたいのかを識別し、コピーします。このクローンオブジェクトでは、すべての属性とオブジェクト属性は、クローン化された同じですが、これらの同じ性質は、2つのタイプに分けられます。
最初:8つのプリミティブ型と(Stringなど)不変オブジェクト
第二:他のオブジェクト
何の問題もなく、元のオブジェクトの値に対する値の第一、クローン方法。第二のために、クローンの方法は、単に新しいオブジェクト参照は、元のオブジェクトの基準点を指すコピー、第二クラス・オブジェクトは、2つのオブジェクトが変更されます。さて、今回はそれが色合いのコピーの概念を含んでいます。
(B)シャローコピー
シャローコピー:すべての変数は、オブジェクトは元のオブジェクトと同じ値が含まれてコピーされ、他のオブジェクトへのすべての参照は、まだ元のオブジェクトを指しています。言い換えれば、唯一の浅いコピーは、検討中のオブジェクトをコピーしますが、それの参照がコピーされていないオブジェクト。
例えばように、クラスA、クラスBは、可変の別のタイプを有しています。書き換えクローン関数呼び出しsuper.cloneは、新しいオブジェクトが作成され、タイプBの元のオブジェクトのクラス変数が同じである場合には、それらは同じタイプBの変数を指します。A内の変数Bは、変更を加えた場合、変数Bは、新しいオブジェクトうちの同じコピーに変更されます。
ダイレクトコールcloneメソッドのsuper.cloneは、すべてが浅いコピーで実現することを忘れないでください。
(III)深いコピー
ディープコピー:すべての変数は、オブジェクトが他のオブジェクトを参照する変数を除去し、元のオブジェクトと同じ値を含むコピーされます。新しいオブジェクトを指すであろう他のオブジェクトを参照する変数ではなく参照される元のオブジェクトよりも、コピーされます。言い換えれば、深い再びコピーされ参照されるオブジェクトをコピーするオブジェクトをコピー。
決勝で他の変数のクラスがある場合、素人の面では、浅いコピー場合は、2行を始め、これは、この変数に一つの共通ポイントへの最後の2行になり、彼に操作することができます。彼は、変数内のすべてのオブジェクトが再びそれをすべて複製されます入れているので、ディープコピーは、完全に二行、互いに不干渉です。
コード内のディープコピー、クローンプロセス変数内の他のクラスにこのクラスの複数のクローン関数呼び出しを記述する必要があります。
(IV)深いコピーのシリアライゼーション
枠組みの中で、我々は時々cloneメソッドをオーバーライドしていなかった、そして我々はそれを動作させる方法である時間内にオブジェクトをコピーする必要があることがわかりましたか?答えは、私たちは、多くの場合、Serializableインタフェースを実現するためのシリアル化メソッドを使用することです。
説得力のある状況は、伝統的な深いコピーならば、あなたは多くの層はなぜ、すべてのオブジェクト変数のコピーを完了するためにどの追撃にオブジェクトをコピーしますされて深いコピーを置き換えるために、他の方法を探すために?これを消費する時間をさておき、単にコードが困難なことになるの書き込み。ディープコピー逐次は、このような比較的簡単な方法です。
ストリームに書き込まれたオブジェクトがシリアライズ(Serilization)プロセスの過程にありますが、Javaプログラマの円と非常に適切と呼ばれる「凍結」や「漬物(ピック)」プロセス、およびオブジェクトがストリームから読み込まれます並列化のうち、(直列化復元)プロセスは、「解凍」または「バック新鮮(depicking)」プロセスと呼ばれています。ストリームがオブジェクトのコピーで記述され、元のオブジェクトは、まだ内部JVMに存在するので、「漬け漬物に」オブジェクトの単なるコピーであるされ、Javaの漬物も新鮮なバックアップできることに留意すべきです。
上記の私は不法侵入にここにないんだけど、オンライン専門の説明です。ディープコピーJava言語でオブジェクト、Serializableインタフェースを実装して、多くの場合、最初のオブジェクトは、そのオブジェクト(オブジェクトの実際にはコピーが)(ピクルスに漬け)ストリームに書き込まれ、その後、ストリーム(バック漬物から読み込まれます新鮮)、我々は、オブジェクトを再構築することができます。
1
2
3
4
5
6
7
8
9
10
11
|
public
Object deepClone()
{
//写入对象
ByteArrayOutoutStream bo=
new
ByteArrayOutputStream();
ObjectOutputStream oo=
new
ObjectOutputStream(bo);
oo.writeObject(
this
);
//读取对象
ByteArrayInputStream bi=
new
ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi=
new
ObjectInputStream(bi);
return
(oi.readObject());
}
|
この学術コードが流れ、チャンスにオブジェクトを複雑に見えますが、実際にけれども。無数のクローンを決定するために比較分析、これは単に簡単なことではありません。これは、オブジェクトへのすべてのオブジェクトと内部オブジェクト参照が直列化可能であることを前提とし、そうでない場合、あなたは慎重にそれらの非直列化されたオブジェクトは過渡的に設定されているかどうかを検討する必要があります。
transient:一个对象只要实现了Serilizable接口,这个对象就可以被序列化(序列化是指将java代码以字节序列的形式写出,即我们上面代码前三行写入对象),Java的这种序列化模式为开发者提供了很多便利,可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个的所有属性和方法都会自动序列化。但是有种情况是有些属性是不需要序列号的,所以就用到这个关键字。只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。