JAVA 对象克隆clone

      有时候我们希望克隆一个已存在的对象,并对其进行操作,但是不希望改变原对象,这时使用clone技术就非常方便了。但是使用clone,也有一些需要注意的地方,因为clone有浅层克隆和深层克隆。还是习惯先直接上代码,结合代码讲解。

      注:如果你希望某个类具有clone功能,该类必须实现接口Cloneable,它是一个标识接口,告诉JVM,这个类具有clone权利。

      为了方便测试,以下代码写得很随便,没有按照规范些,呵呵。

public class A implements Cloneable{

	//为了方便测试,以下变量都用public修饰
	public int num;
	public String name;
	public String[] nickNames=new String[2];
	public B b=new B();
	
	public A clone(){
		A a=null;
		try{
			a=(A)super.clone();
		}catch(CloneNotSupportedException e){
			e.printStackTrace();
		}
		return a;
	}
}
public class B {

	//为了方便测试,变量用public修饰
	public String name;
}
public class C {

	public static void main(String[] args){
		A a1=new A();
		//给a1的属性设值
		a1.num=10;
		a1.name="a1";
		a1.nickNames[0]="a1-1";
		a1.nickNames[1]="a1-2";
		a1.b.name="a1.b";
		//打印a1
		System.out.println("a1克隆前:");
		print(a1);
		A a2=a1.clone();	
		//给a2属性设值
		a2.num=20;
		a2.name="a2";
		a2.nickNames[0]="a2-1";
		a2.nickNames[1]="a2-2";
		a2.b.name="a2.b";
		//打印a2
		System.out.println("克隆对象a2:");
		print(a2);
		//再打印a1
		System.out.println("a1克隆后:");
		print(a1);
	}
	public static void print(A a){
		System.out.println("num="+a.num+"    name="+a.name+"   nickNames[0]="+a.nickNames[0]
				+"    nickNames[1]="+a.nickNames[1]+"    b.name="+a.b.name);
	}
}

看看运行结果:

a1克隆前:
num=10    name=a1   nickNames[0]=a1-1    nickNames[1]=a1-2    b.name=a1.b
克隆对象a2:
num=20    name=a2   nickNames[0]=a2-1    nickNames[1]=a2-2    b.name=a2.b
a1克隆后:
num=10    name=a1   nickNames[0]=a2-1    nickNames[1]=a2-2    b.name=a2.b

发现a1除了int num,String name的内容没变,其它都变了,这是怎么回事呢?这就是所谓的浅层克隆,也就是克隆不彻底,画张草图表示下.

发现虽然引用对象a1和引用对象a2都指向了各自的实例对象,但是他们的实例对象内部的数组对象和类对象引用(除了String)都指向了同一处。为了解决这问题,就需要深层克隆。

A代码修改如下。

public class A implements Cloneable{

	//为了方便测试,以下变量都用public修饰
	public int num;
	public String name;
	public String[] nickNames=new String[2];
	public B b=new B();
	
	public A clone(){
		A a=null;
		try{
			a=(A)super.clone();
			a.nickNames=new String[this.nickNames.length];//重新new一个
			System.arraycopy(this.nickNames, 0, a.nickNames, 0, this.nickNames.length);//复制
			a.b=(B)this.b.clone();//B克隆
		}catch(CloneNotSupportedException e){
			e.printStackTrace();
		}
		return a;
	}
}


由于A中对B进行了克隆,所以B也必须实现接口Cloneable

public class B implements Cloneable{

	//为了方便测试,变量用public修饰
	public String name;
	public B clone(){
		B b=null;
		try{
			b=(B)super.clone();
			
		}catch(CloneNotSupportedException e){
			e.printStackTrace();
		}
		return b;
	}
}


测试类C不需修改,再看看运行结果。

a1克隆前:
num=10    name=a1   nickNames[0]=a1-1    nickNames[1]=a1-2    b.name=a1.b
克隆对象a2:
num=20    name=a2   nickNames[0]=a2-1    nickNames[1]=a2-2    b.name=a2.b
a1克隆后:
num=10    name=a1   nickNames[0]=a1-1    nickNames[1]=a1-2    b.name=a1.b

发现a2就算进行了修改也无法影响到a1了,这就是我们要的效果

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值