对象克隆的分析

趁着暑假两个月闲时间,想对自己的JAVA SE知识夯实一下,抱着《JAVA 2核心技术》啃。现在已经把上卷搞定了,都是一些基础内容,但却受益匪浅,现在可以整理一下这个月的感悟了。

今天要说的是对象的克隆。在JAVA中对象的克隆有的时候是必要的,克隆可以获得相同对象的不同引用,即它们是相互独立的,克隆分两种:浅克隆、深克隆。浅克隆指如果对象中含有非基本类型的成员,那么克隆的对象与源对象共用该成员的引用,即在两个对象中该成员的引用是一样的。这种克隆是相对意义上的克隆,克隆的对象与源对象并没有绝对的独立。深克隆指克隆的对象与源对象在所有的成员上都有不同引用,实现了绝对意义上的克隆。浅克隆比起深克隆来很容易实现。下面先说浅克隆。

浅克隆的实现非常的简单:待克隆的类需实现java.lang.Cloneable接口,该接口无待实现的方法,只是一种标记。然后覆盖Object类的clone()方法,在方法中调用Object的clone()即可。下面是测试的类代码。

/*
 * Grade类保存成绩,作为本次测试中CloneTest类中的成员
 */
public class Grade {
	private int grade;
	
	public Grade(){
	}
	
	public Grade(int grade){
		this.grade = grade;
	}
	
	public void setGrade(int grade){
		this.grade = grade;
	}
	
	public int getGrade(){
		return this.grade;
	}
	
	public String toString(){
		return "Grade is "+grade;
	}
}
/*
 * CloneTest类是测试克隆的主类
 */
public class CloneTest implements Cloneable{
	
	private Grade g;
	
	public CloneTest(Grade g){
		this.g = g;
	}
	
	public Grade getG() {
		return g;
	}


	public void setG(Grade g) {
		this.g = g;
	}

	public Object clone(){
			try {
				return super.clone();
			} catch (CloneNotSupportedException e) {
				e.printStackTrace();
				return null;
			}
	}

	public static void main(String[] args) {
		CloneTest ct = new CloneTest(new Grade(6));
		CloneTest ctClone = (CloneTest)ct.clone();
		ct.getG().setGrade(8);
		System.out.println(ctClone.getG().toString());
	}
}

运行上述代码可发现,输出是“Grade is 8”,即修改ct对象中的Grade对象引用,也影响到了被克隆出来的ctClone对象中的Grade对象,证明了之前对浅克隆的描述。

空白如果如下修改上述代码。

import java.io.Serializable;

/*
 * Grade类保存成绩,作为本次测试中CloneTest类成员
 */
public class Grade implements Serializable{
	private int grade;
	
	public Grade(){
	}
	
	public Grade(int grade){
		this.grade = grade;
	}
	
	public void setGrade(int grade){
		this.grade = grade;
	}
	
	public int getGrade(){
		return this.grade;
	}
	
	public String toString(){
		return "Grade is "+grade;
	}
}
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;


/*
 * CloneTest类是测试克隆的主类
 */
public class CloneTest implements Cloneable,Serializable{
	
	private Grade g;
	
	public CloneTest(Grade g){
		this.g = g;
	}
	
	public Grade getG() {
		return g;
	}


	public void setG(Grade g) {
		this.g = g;
	}

	public Object clone(){
		try{
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(baos);
			oos.writeObject(this);
			oos.close();
			
			ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
			ObjectInputStream ois = new ObjectInputStream(bais);
			Object resultObject = ois.readObject();
			ois.close();
			
			return resultObject;
		}
		catch(Exception e){
			e.printStackTrace();
			return null;
		}
	}

	public static void main(String[] args) {
		CloneTest ct = new CloneTest(new Grade(6));
		CloneTest ctClone = (CloneTest)ct.clone();
		ct.getG().setGrade(8);
		System.out.println(ctClone.getG().toString());
	}
}

运行代码,如你所看到的结果“Grade is 6”,修改后的CloneTest真正意义上的实现了克隆,ct对象的Grade引用与ctClone的不同,它们相互独立,彼此互不影响。分析后会发现在实现clone方法时与之前的不同,现在先是把CloneTest的对象放到输出流中,然后再从输出流中读入,这样就实现了深克隆。实现的思路很简单,是从《JAVA 2核心技术》中看到的,书上也提到了性能问题,这种实现的弊端就是对待简单的对象不如直接的构造新的对象然后拷贝或是克隆数据域的方法来的快。

说到这里已经把浅克隆和深克隆的区别和实现方法讲完了。

PS:之前在看到《JAVA 2核心技术》使用反射技术实现通用的toString()方法,在想是否也可以使用反射技术通过递归的拷贝类的数据域以实现通用的clone()方法,发现如果使用反射,那对于较复杂的类来说,工作量是巨大的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值