克隆介绍
开发过程中可能需要对一些复杂对象进行拷贝复制或者在给调用者返回数据的同时,调用者对返回数据进行修改不会影响原始数据的情况下就会使用clone对数据进行克隆;实现Cloneable 接口并重写clone方法;因为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());
}
}
运行结果
画图分析
首先栈存在一个inner和outter对象,分别指向堆内存中一个地址,这里分别使用0x****1
和0x*****2
区分;克隆后栈中会创建一个clOuter对象引用,堆内存中开辟一片新的内存地址0x****3
,将被克隆对象的outterint和outterString的属性值拷贝赋值,引用类型的值因为存的是地址(0x1),所以拷贝过来也就和被克隆对象一样指向0x1;所以修改克隆后对象的引用类型的对象的属性,相当于操作的同一个inner对象,所以会影响到被拷贝对象的引用类型属性的对象的值
深克隆
深克隆是在浅克隆的基础上,对引用类型的属性值(代码中的Inner对象)进行克隆,这样被克隆的引用类型的属性值和克隆后的引用类型的属性值就指向的堆内存中不同的地址;从而修改克隆后引用类型的属性值并不会影响被克隆对象的对应的属性值;
代码上就是让引用类型对象也实现Cloneable 接口并重写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());
}
}
运行结果
画图分析
在浅克隆基础上,对被克隆对象的引用类型属性的对象进行再次克隆,这样被克隆对象和克隆后的对象中的引用类型属性值就指向了堆内存中不同的地址(0x1,0x3),这样修改克隆后对象的引用类型属性对象的值(0x****3)就不会影响到被克隆对象的引用类型属性对象的值
参考:
Cloneable接口的作用与深入理解深度克隆与浅度克隆
Java中clone( )和new效率比较
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/18736.html