Java克隆

Java克隆技术详解
本文深入探讨了Java中的克隆技术,包括浅克隆和深克隆的概念与实现方式。详细解释了浅克隆在复制对象时仅复制顶层对象,而深克隆则彻底复制所有层级的对象。介绍了通过序列化实现深克隆的推荐方法。


Java 有两种克隆,浅克隆和深克隆
浅克隆
负责拷贝当前对象,但是对象里的对象没法克隆,还是引用该对象的对象变量。
深克隆
负责拷贝当前对象,并且对象的对象也被克隆,既不再引用对象的对象,而是一个新的对象的对象。

浅克隆

使用方法,克隆类实现Cloneable接口,然后重写祖宗类Object的clone()方法;
实现cloneable接口的方法是因为:Cloneable类似于虚拟机的一个表示接口,必须得以实现,才能进行clone,l类似的接口还有Serializable接口。
**重写clone()方法:**将clone()方法的权限扩大为public,这样在其他的类中就可以直接试用clone()方法。

学生类,在这里除了基本变量外,还引用了一个类变量 address;

@SuppressWarnings("serial")
class Student implements Cloneable{                //实现cloneable接口
	private int age;
	private String name;
	private Address address;

	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	
	public IStudent clone() throws CloneNotSupportedException {    //重写clone方法
		return (IStudent) super.clone();
	}
}

地址类

@SuppressWarnings("serial")
public class Address{
	private int code;
	private String country;
	
	public int getCode() {
		return code;
	}
	public void setCode(int code) {
		this.code = code;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
}

开始拷贝

public class ShallowCopy {
	public static void main(String[] args) throws CloneNotSupportedException {
		//生成一个新的地址对象
		Address address = new Address();
		address.setCode(86);
		address.setCountry("CN");
			
		//将该地址赋值给学生1
		Student stu = new Student();
		stu.setAddress(address);

		//学生2克隆学生一
		IStudent stud = stu.clone();     //clone是浅拷贝,当对象中的对象改变时,会影响clone的对象
		
		//改变学生1的地址
		stu.getAddress().setCode(01);
		stu.getAddress().address.setCountry("US");

		//输出学生2的地址,实际上学生2的地址没有变
		System.out.println(stu.getAddress().getCountry()+ ":" +stud.getAddress().getCountry());
	}
}

输出结果

US : 01

意味着,当改变学生1的地址的同时会改变学生2的地址,因为浅拷贝只能克隆表层对象,而address是深层对象,但是基本变量的age 和 final修饰的String不受影响。

结论

如果拷贝的对象的属性都是基本变量或者是单一层次的对象,则可以使用浅克隆,如果有深层对象,例如Address则不能使用浅克隆,只能使用深克隆。

在这里插入图片描述

深拷贝

两种,一种是在多层浅拷贝对象中的对象,另一种就是通过反序列化实现深克隆

普通深克隆

也就是多层浅克隆

class Students implements Cloneable{            //实现cloneable接口,浅克隆条件一
	private int age;
	private String name;
	private IAddress address;
	
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public IAddress getAddress() {
		return address;
	}
	public void setAddress(IAddress address) {
		this.address = address;
	}
	
	public Students clone() throws CloneNotSupportedException {	                      //重写object的clone()方法,浅克隆的条件2
		return (Students) super.clone();                                                    
	}
}

为了实现深克隆,所以,Iadress类也需要实现深克隆

public class IAddress implements Cloneable{                                            //同样先实现cloneable接口
	private int code;
	private String country;
	
	public int getCode() {
		return code;
	}
	public void setCode(int code) {
		this.code = code;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	
	@Override
	public IAddress clone() throws CloneNotSupportedException {                               //然后重写object的object()方法
		return (IAddress) super.clone();                                                        
	}
}

执行深克隆

public class DeepCopy {
	public static void main(String[] args) throws CloneNotSupportedException {
		Students stu = new Students();
		IAddress address = new IAddress();
		address.setCode(86);
		address.setCountry("CN");
		stu.setAddress(address);
		Students stud = stu.clone();
		stud.setAddress(address.clone());                 //同时需要对其子对象进行拷贝,在复杂的对象包含关系中不适用
		address.setCode(01);
		address.setCountry("US");
		System.out.println(stud.getAddress().getCountry() + ":" + stud.getAddress().getCode());
	}
}

输出结果

01:US                                  //两个对象完全克隆,对象中的对象,互相不受影响。

实现序列化完成深克隆拷贝(推荐)

通过将对象序列化,之后反序列化回来生成新的对象。
步骤

  1. 实现serializalble接口
  2. 通过序列化和反序列化生成新的对象

IStudent类实现了cloneable接口和Serializable接口

@SuppressWarnings("serial")
class IStudent implements Serializable{
	private int age;
	private String name;
	private Address address;
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}

通过序列化进行深clone的拷贝

public class SerializationDeepCopy {
	public static void main(String[] args) {
		IStudent stu = new IStudent();
		Address address = new Address();
		address.setCode(86);
		address.setCountry("CN");
		stu.setAddress(address);
		IStudent stud = deepCopy(stu);
		address.setCode(01);
		address.setCountry("US");
		System.out.println(stud.getAddress().getCountry() + ":" + stu.getAddress().getCountry());
	}
	
	@SuppressWarnings("unchecked")
	public static <T extends Serializable> T deepCopy(IStudent stu) {                               //进行序列化和反序列化操作
		IStudent student = null;
		try
		{
			ByteArrayOutputStream bios = new ByteArrayOutputStream();
			ObjectOutputStream os = new ObjectOutputStream(bios);
			os.writeObject(stu);
			ByteArrayInputStream ios = new ByteArrayInputStream(bios.toByteArray());
			ObjectInputStream ois = new ObjectInputStream(ios);
			student = (IStudent) ois.readObject();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return (T) student;
		
	}
}

输出结果

01:US               //完全克隆原来的对象

也可以直接调用org.apache.commons.lang3.SerializationUtils中的方法来进行生克隆
在子类中加上

class StudentI implements Cloneable,Serializable{
	
	private int age;
	private String name;
	
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	
	@Override
	protected Object clone() throws CloneNotSupportedException {          
		return SerializationUtils.clone(this);                                                 //将该方法直接重写到clone()方法
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值