Java-克隆数组

背景

克隆是为了解决别名带来的问题。别名问题是,把一个句柄赋值给另一个句柄,我们利用这两个句柄

都可以修改同一个对象,有时候我们并不想原来的对象被修改,所以就可以用克隆的技术来解决。

在克隆数组的时候比较容易出问题,所以就把我碰到的问题记录下来,跟大家一起分享。

1.看源码

package c12;

class Battery implements Cloneable{
	  int number;
	  public Battery(int number){
		  this.number=number;
	  }
	  //覆盖克隆方法:
	  public Object clone(){
		  Object o=null;
		  try{
			  o=super.clone();
		  }catch(CloneNotSupportedException e)
		  {
			  e.printStackTrace();
		  }
		  return o;
	  }
}

 class CopyToy implements Cloneable {
	 
	Battery[] bt={new Battery(0),new Battery(1),
				new Battery(2),new Battery(3),new Battery(4)};
	//覆盖克隆方法:
	public Object clone() {
		CopyToy t=null;
		try{
			t=(CopyToy)super.clone();
		}catch(CloneNotSupportedException e)
		{
			  e.printStackTrace();
		}
//		t.bt=(Battery[])t.bt.clone();	
		for(int i=0;i<t.bt.length;i++)
			t.bt[i]=(Battery)t.bt[i].clone();
		return t;
	}
	//该方法用来克隆CopyToy,修改number的值
	public  CopyToy change(CopyToy t){
		t=(CopyToy)t.clone();
		for(int i=0;i<t.bt.length;i++)
			t.bt[i].number++;
		return t;
	}
	//覆盖 toSring() 方法
	public String toString(){
		String s="";
		for(int i=0;i<bt.length;i++)
			s+=Integer.toString(bt[i].number);
		return s;
	}
	
}
 public class Toy{
	 public static void main(String[] args){
		 CopyToy ct=new CopyToy();	 
		 System.out.println("Before change(ct):	" +ct);	 
		 ct.change(ct);	 
		 System.out.println("After change(ct):	"+ct);	 
	 }
 }

运行结果:

2.分析

这里写了一个Battery类和CopyToy类,都覆盖了克隆的方法,具体的克隆语法如下:

(1)实现 Cloneable接口

(2)覆盖克隆方法: public Object clone()  

(3)调用super.clone(),记得处理违例。

然后用Toy类来测试,通过调用change()方法改变Battery.number的值,然后再打印

出ct修改前后的值。

Battery[] bt={new Battery(0),new Battery(1),
				new Battery(2),new Battery(3),new Battery(4)};
//覆盖克隆方法:
	public Object clone() {
		CopyToy t=null;
		try{
			t=(CopyToy)super.clone();
		}catch(CloneNotSupportedException e)
		{
			  e.printStackTrace();
		}
//		t.bt=(Battery[])t.bt.clone();	
//克隆数组:
		for(int i=0;i<t.bt.length;i++)
			t.bt[i]=(Battery)t.bt[i].clone();
		return t;
	}

在CopyToy的类的clone()方法中,调用了(CopyToy)super.clone(),返回的是一个Object对象然后造型成

CopyToy,以便获得CopyToy句柄,这里的克隆是浅克隆,因为当我们调用change()的时候,原来对象的

Battery.number的值是会改变的,也就是说我们还得克隆Battery数组(基本类型不用克隆,而数组

是对象需要克隆)。

for(int i=0;i<t.bt.length;i++)
	t.bt[i]=(Battery)t.bt[i].clone();

通过上面的代码我们克隆了数组。但是运行的结果中,我们的对象还是被我们改变了,我们要做的是克隆

对象,不改变原来的对象,这样才能解决别名问题。

通过测试,我发现 t.bt 和 t.bt[0] 对象的地址是不一样的,但是我们学习过C就会发现这两个地址是一样的,在java

中这种观念要转变一下,别被坑了。

下面图是来自https://www.2cto.com/kf/201801/715942.html

看上面的图我们可以再分析一下,t.bt[0]是包含在t.bt对象里面的,然而我们克隆数组的代码中没有克隆

t.bt对象,所以结果就会出错。

我们把下面这个语句的注释去掉,再编译一下,结果是ct的值不会变,这样就达到了深度克隆的效果,

也解决了别名的问题。

//		t.bt=(Battery[])t.bt.clone();	

总结

我们在克隆数组的时候,数组的句柄也要一起克隆,否则会出现错误。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值