クローニング入門
開発プロセス中に、いくつかの複雑なオブジェクトをコピーする必要がある場合があります。または、データを呼び出し元に返すときに、返されたデータの変更が元のデータに影響を与えない場合、呼び出し元はクローンを使用してデータのクローンを作成します。クローン可能インターフェイスを実装し、クローンメソッドを書き直します。javaで値を渡す問題があるため、クローンは浅いクローンと深いクローンに分けられます。
浅いクローン
浅いクローン作成は、ヒープメモリにオブジェクトを作成し、クローン作成されたオブジェクトのすべての属性値(基本タイプの値と参照タイプの参照値を含む)を新しいオブジェクトに割り当てます;の属性を変更します複製された基本型は、複製されたオブジェクトの対応するプロパティに影響を与えません。複製された参照型のプロパティを変更すると、対応する複製されたオブジェクトのプロパティに影響を与えます。
package test;
public class CloneTest {
public static class Outer implements Cloneable {
private int outerInt;
private String outerString;
private Inner inner = null;
public int getOuterInt() {
return outerInt;
}
public void setOuterInt(int outerInt) {
this.outerInt = outerInt;
}
public String getOuterString() {
return outerString;
}
public void setOuterString(String outerString) {
this.outerString = outerString;
}
public Inner getInner() {
return inner;
}
public void setInner(Inner inner) {
this.inner = inner;
}
@Override
public String toString() {
return "Outer [outerInt=" + outerInt + ", outerString=" + outerString + ", inner=" + inner + "]";
}
@Override
protected Outer clone() throws CloneNotSupportedException {
return (Outer) super.clone();
}
}
public static class Inner {
int innerInt;
String innerString;
public int getInnerInt() {
return innerInt;
}
public void setInnerInt(int innerInt) {
this.innerInt = innerInt;
}
public String getInnerString() {
return innerString;
}
public void setInnerString(String innerString) {
this.innerString = innerString;
}
@Override
public String toString() {
return "Inner [innerInt=" + innerInt + ", innerString=" + innerString + "]";
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Inner inner = new Inner();
inner.setInnerInt(10);
inner.setInnerString("ceshi_inner");
Outer outer = new Outer();
outer.setOuterInt(11);
outer.setOuterString("ceshi_outter");
outer.setInner(inner);
System.out.println("原始数据---");
System.out.println("Outer: " + outer + " hashcode:" + outer.hashCode());
System.out.println("Outer中inner--hashcode:" + outer.inner.hashCode());
Outer clOuter = outer.clone();
System.out.println("克隆后---");
System.out.println("clOuter: " + clOuter + " hashcode:" + clOuter.hashCode());
System.out.println("clOuter中inner--hashcode:" + clOuter.inner.hashCode());
clOuter.setOuterInt(12);
clOuter.setOuterString("ceshi_clOuter");
clOuter.inner.setInnerInt(13);
clOuter.inner.setInnerString("ceshi_clInner");
System.out.println("克隆后修改数据,然后对比克隆后的对象和克隆前的对象---");
System.out.println("---------------------------被克隆对象---------------------------");
System.out.println("Outer: " + outer + " hashcode:" + outer.hashCode());
System.out.println("Outer中inner--hashcode:" + outer.inner.hashCode());
System.out.println("---------------------------克隆的对象---------------------------");
System.out.println("clOuter: " + clOuter + " hashcode:" + clOuter.hashCode());
System.out.println("clOuter中inner--hashcode:" + clOuter.inner.hashCode());
}
}
運転結果
描画分析
まず、スタックに内部オブジェクトと外部オブジェクトがあり、ヒープメモリ内のアドレスを指します。これらはここで使用され0x****1
、0x*****2
区別されます。クローン作成後、clOuterオブジェクト参照がスタックに作成され、新しいメモリが作成されます。アドレス0x****3
がヒープメモリで開かれ、オブジェクトがクローン化されます.outterintとoutterStringの属性値がコピーされて割り当てられます。参照タイプの値がアドレス(0x 1)に格納されているため、コピーまた、クローンオブジェクトとして0x 1を指します。したがって、クローンオブジェクトの参照タイプのオブジェクトの属性を変更します。これは、操作の同じ内部オブジェクトと同等であり、オブジェクトの参照タイプの値に影響します。コピーされたオブジェクトの属性
ディープクローン
ディープクローニングとは、シャロークローンに基づいて参照タイプ(コード内の内部オブジェクト)の属性値を複製することです。これにより、複製された参照タイプの属性値とクローンされた参照タイプの属性値は、ヒープメモリ異なるアドレス。したがって、クローン作成後に参照タイプの属性値を変更しても、クローン作成されたオブジェクトの対応する属性値には影響しません。
コードは、参照型オブジェクトにCloneableインターフェイスも実装させ、cloneメソッドを書き直し、オブジェクトの内部参照型属性オブジェクトのクローンをcloneされたオブジェクトのcloneメソッドに追加することです。直感的に理解できるのは、オブジェクトがクローン化されるときです。 、内部参照型属性オブジェクトのクローン化でもあります
package test;
public class CloneTest {
public static class Outer implements Cloneable {
private int outerInt;
private String outerString;
private Inner inner = null;
public int getOuterInt() {
return outerInt;
}
public void setOuterInt(int outerInt) {
this.outerInt = outerInt;
}
public String getOuterString() {
return outerString;
}
public void setOuterString(String outerString) {
this.outerString = outerString;
}
public Inner getInner() {
return inner;
}
public void setInner(Inner inner) {
this.inner = inner;
}
@Override
public String toString() {
return "Outer [outerInt=" + outerInt + ", outerString=" + outerString + ", inner=" + inner + "]";
}
@Override
protected Outer clone() throws CloneNotSupportedException {
Outer outer = (Outer) super.clone();
outer.inner = outer.inner.clone();
return outer;
}
}
public static class Inner implements Cloneable {
int innerInt;
String innerString;
public int getInnerInt() {
return innerInt;
}
public void setInnerInt(int innerInt) {
this.innerInt = innerInt;
}
public String getInnerString() {
return innerString;
}
public void setInnerString(String innerString) {
this.innerString = innerString;
}
@Override
public String toString() {
return "Inner [innerInt=" + innerInt + ", innerString=" + innerString + "]";
}
@Override
protected Inner clone() throws CloneNotSupportedException {
return (Inner) super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Inner inner = new Inner();
inner.setInnerInt(10);
inner.setInnerString("ceshi_inner");
Outer outer = new Outer();
outer.setOuterInt(11);
outer.setOuterString("ceshi_outter");
outer.setInner(inner);
System.out.println("原始数据---");
System.out.println("Outer: " + outer + " hashcode:" + outer.hashCode());
System.out.println("Outer中inner--hashcode:" + outer.inner.hashCode());
Outer clOuter = outer.clone();
System.out.println("克隆后---");
System.out.println("clOuter: " + clOuter + " hashcode:" + clOuter.hashCode());
System.out.println("clOuter中inner--hashcode:" + clOuter.inner.hashCode());
clOuter.setOuterInt(12);
clOuter.setOuterString("ceshi_clOuter");
clOuter.inner.setInnerInt(13);
clOuter.inner.setInnerString("ceshi_clInner");
System.out.println("克隆后修改数据,然后对比克隆后的对象和克隆前的对象---");
System.out.println("---------------------------被克隆对象---------------------------");
System.out.println("Outer: " + outer + " hashcode:" + outer.hashCode());
System.out.println("Outer中inner--hashcode:" + outer.inner.hashCode());
System.out.println("---------------------------克隆的对象---------------------------");
System.out.println("clOuter: " + clOuter + " hashcode:" + clOuter.hashCode());
System.out.println("clOuter中inner--hashcode:" + clOuter.inner.hashCode());
}
}
実行結果の
描画分析
浅い複製に基づいて、複製されたオブジェクトの参照型属性のオブジェクトが再度複製されるため、複製されたオブジェクトと複製されたオブジェクトの参照型属性値は、ヒープメモリ内の異なるアドレスを指します。 (0x 1、0x 3)、クローンオブジェクトの参照タイプ属性オブジェクトの値を変更しても(0x **** 3)、クローンオブジェクトの参照タイプ属性オブジェクトの値に影響を与えないようにします。
参照:
クローン可能インターフェースの役割、ディープクローンとシャロークローンのJava clone()の詳細な理解、
および新しい効率の比較