Java 对象克隆

本文深入探讨了Java中对象克隆的基本概念,包括浅克隆和深克隆的区别及实现方式,通过具体代码示例解释了如何对引用类型进行正确克隆,避免对象间状态的意外共享。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对于8种基本类型和String类型来说,克隆一般为以下:

int a = 10;
int b = a; 

而对于引用类型,就相对复杂一些
定义一个测试类CloneDemo:

public class CloneDemo {
	int id;
	String name;
	public CloneDemo(int id, String name){
		this.id = id;
		this.name = name;
	}
	@Override
	public String toString() {
		return "CloneDemo [id=" + id + ", name=" + name + "]";
	}
}

测试:

CloneDemo demo = new CloneDemo(1, "clone1");
CloneDemo demo1 = demo;
demo1.name = "clone2";
System.out.println(demo.toString());
System.out.println(demo1.toString());

结果:

CloneDemo [id=1, name=clone2]
CloneDemo [id=1, name=clone2]

可以看出实例demo和demo1, 引用相同的地址。所以对于引用类型克隆,不能使用一般的“=”。其在内存中表示为:
在这里插入图片描述

对于引用类型的克隆有浅克隆和深克隆。
浅克隆:当对象克隆时,只复制对象本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
具体实现:

  1. 被复制的类需要实现Clonenable接口并重写clone()方法
public class CloneDemo implements Cloneable{
	int id;
	String name;
	public CloneDemo(int id, String name){
		this.id = id;
		this.name = name;
	}
	@Override
	public String toString() {
		return "CloneDemo [id=" + id + ", name=" + name + "]";
	}
	
	@Override
	public Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
				return super.clone();
	}
}

测试:

CloneDemo demo = new CloneDemo(1, "clone1");
CloneDemo demo1 = (CloneDemo) demo.clone();
demo1.name = "clone2";
System.out.println(demo.toString());
System.out.println(demo1.toString());

结果:

CloneDemo [id=1, name=clone1]
CloneDemo [id=1, name=clone2]

但是当对象中含有引用类型的成员变量时,当进行克隆时只是将引用类型成员的地址进行拷贝。

public class CloneInfo implements Cloneable{	
	private String infor;
	// 省略 get和set, 构造函数
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
}


public class CloneDemo implements Cloneable{
	
	int id;
	String name;
	// 引用类型成员
	CloneInfo info;
	
	// 省略 get和set, 构造函数
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}

	@Override
	public String toString() {
		return "CloneDemo [id=" + id + ", name=" + name + ", info=" + info.getInfor() + "]";
	}
}


	public static void main(String[] args) throws Exception {

		CloneDemo demo = new CloneDemo(1,"clone1",new CloneInfo("cloneInfo1"));
		CloneDemo demo1 =  (CloneDemo) demo.clone();
		System.out.println(demo.toString());
		System.out.println(demo1.toString());
		
		demo1.setName("clone2");
		demo1.getInfo().setInfor("cloneInfo2");
		
		System.out.println(demo.toString());
		System.out.println(demo1.toString());
}

结果:

CloneDemo [id=1, name=clone1, info=cloneInfo1]
CloneDemo [id=1, name=clone1, info=cloneInfo1]
CloneDemo [id=1, name=clone1, info=cloneInfo2]
CloneDemo [id=1, name=clone2, info=cloneInfo2]

所以此时应该使用深克隆,实现深克隆有两种方法:
1.实现Cloneable接口
2.实现Serializable接口

实现Cloneable接口
public class CloneInfo implements Cloneable{
   private String infor;
   public CloneInfo(String info) {
   	this.infor = info;
   }
   public String getInfor() {
   	return infor;
   }
   public void setInfor(String infor) {
   	this.infor = infor;
   }
   @Override
   protected Object clone() throws CloneNotSupportedException {
   	// TODO Auto-generated method stub
   	return super.clone();  // 主要方法
   }

}

public class CloneDemo implements Cloneable{
...
   @Override
   protected Object clone() throws CloneNotSupportedException {
   	// TODO Auto-generated method stub
   	CloneDemo demo = (CloneDemo)super.clone();
   	demo.info = (CloneInfo)info.clone();   // 引用类型成员变量进行克隆
   	return demo;
   }

}

结果:

CloneDemo [id=1, name=clone1, info=cloneInfo1]
CloneDemo [id=1, name=clone1, info=cloneInfo1]
CloneDemo [id=1, name=clone1, info=cloneInfo1]
CloneDemo [id=1, name=clone2, info=cloneInfo2]
实现Serializable接口
public class CloneDemo implements Serializable{
	
	private static final long serialVersionUID = 1L;
	
	int id;
	String name;
	CloneInfo info;
	
// 省略 get和set, 构造函数
	
	@Override
	public String toString() {
		return "CloneDemo [id=" + id + ", name=" + name + ", info=" + info.getInfor() + "]";
	}
}


public class CloneInfo implements Serializable{

	private static final long serialVersionUID = 1L;
	
	private String infor;
	
// 省略 get和set, 构造函数
}


public static void main(String[] args) throws Exception {
		
		CloneDemo demo = new CloneDemo(1,"clone1",new CloneInfo("cloneInfo1"));
		
		CloneDemo demo1 =  CloneUtil.clone(demo);
		System.out.println(demo.toString());
		System.out.println(demo1.toString());
		
		demo1.setName("clone2");
		demo1.getInfo().setInfor("cloneInfo2");
		
		System.out.println(demo.toString());
		System.out.println(demo1.toString());
	}

结果:

CloneDemo [id=1, name=clone1, info=cloneInfo1]
CloneDemo [id=1, name=clone1, info=cloneInfo1]
CloneDemo [id=1, name=clone1, info=cloneInfo1]
CloneDemo [id=1, name=clone2, info=cloneInfo2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值