`

java中的clone机制及序列化

阅读更多

    在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,AB是两个独立的对象,但B的初始值是由A对象确定的。在这种情况下常常使用clone。当然你完全可以new一个新的,让后再进行赋值。但应用clone会有如下的好处:

     1、实现clone方法比较简单、方便。

     2、Object类的clone()一个native方法,native方法的效率一般来说都是远高于java中的非native方法,因此clone方法是高效的。

    注意;通过序列化的方式也可以实现clone。如果一个对象包含复杂类型的变量时,可用序列化或深度clone来实现对象的clone。

浅度复制和深度复制

  
    在java中,对于基本类型的数据可采用浅度复制的方式进行对象的复制,其中做法就是直接继承Cloneable接口,调用Object类的clone()方法就可以了。而对于非基本类型的数据,复制方法只能采用深度复制或序列化的方式进行复制。
    典型的实例:
/**
 * 
 * @功能   羊对象类  
 * @创建人   gao_jie
 * @创建日期 Jun 25, 2009
 * @版本     1.0
 * 
 */
public class Sheep implements Cloneable {
	
	private String name;//名字

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}

public class Sheepfold implements Cloneable {
	 public Sheep sheep;//羊对象
	 public String name;//羊圈名字
	 public int number;//数量

	 public Sheepfold() {
		 this.sheep = new Sheep();
	 }
	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}

public class Test {
	public static void main(String[] args) {
		// 声明一个小羊圈对象
		Sheepfold smallFold = new Sheepfold();
		smallFold.name = "小羊圈";
		smallFold.number = 10;
		smallFold.sheep.setName("小羊");
		// 复制羊圈
		Sheepfold bigFold = null;
		try {
			bigFold = (Sheepfold) smallFold.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		bigFold.name="大羊圈";
		bigFold.number=100;
		bigFold.sheep.setName("大羊");
		
		System.out.println("小羊圈输出信息如下:");
		System.out.println("smallFold.name="+smallFold.name);
		System.out.println("smallFold.number="+smallFold.number);
		System.out.println("smallFold.sheep="+smallFold.sheep.getName());
		System.out.println("大羊圈输出信息如下:");
		System.out.println("bigFold.name="+bigFold.name);
		System.out.println("bigFold.number="+bigFold.number);
		System.out.println("bigFold.sheep="+bigFold.sheep.getName());
	}
}
测试结果:
小羊圈输出信息如下:
smallFold.name=小羊圈
smallFold.number=10
smallFold.sheep=大羊
大羊圈输出信息如下:
bigFold.name=大羊圈
bigFold.number=100
bigFold.sheep=大羊
 
显然上面的这种复制是失败的,因为改动第二个对象中的名字后第一个对象的名字也发生了变化。要实现正确的复制,必须采用深度复制。其sheepfold类中clone方法的代码应改为如下:

把上面的例子改成深度clone很简单,只需将Sheepfold的clone()方法改为如下即可:
    public Object clone() throws CloneNotSupportedException {
        Sheepfold fold = (Sheepfold)super.clone();
        sheep = (Sheep)fold.sheep.clone();
        return fold;
    }
 另外,采用序列化也可以实现深度复制的效果。
代码如下:

/**
 * 
 * @功能   羊对象类  
 * @创建人   gao_jie
 * @创建日期 Jun 25, 2009
 * @版本     1.0
 * 
 */
public class Sheep implements Serializable{
	
	private String name;//名字

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

public class Sheepfold implements Cloneable, Serializable {
	public Sheep sheep;// 羊对象
	public String name;// 羊圈名字
	public int number;// 数量

	public Sheepfold() {
		this.sheep = new Sheep();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#clone()
	 */
	public Object clone() throws CloneNotSupportedException {
		try {
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(bos);
			oos.writeObject(this);
			// 将流序列化
			ByteArrayInputStream bis = new ByteArrayInputStream(bos
					.toByteArray());
			ObjectInputStream ois = new ObjectInputStream(bis);
			return ois.readObject();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}
}
测试类
public class Test {
	public static void main(String[] args) {
		// 声明一个小羊圈对象
		Sheepfold smallFold = new Sheepfold();
		smallFold.name = "小羊圈";
		smallFold.number = 10;
		smallFold.sheep.setName("小羊");
		// 复制羊圈
		Sheepfold bigFold = null;
		try {
			bigFold = (Sheepfold) smallFold.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		bigFold.name="大羊圈";
		bigFold.number=100;
		bigFold.sheep.setName("大羊");
		
		System.out.println("小羊圈输出信息如下:");
		System.out.println("smallFold.name="+smallFold.name);
		System.out.println("smallFold.number="+smallFold.number);
		System.out.println("smallFold.sheep="+smallFold.sheep.getName());
		System.out.println("大羊圈输出信息如下:");
		System.out.println("bigFold.name="+bigFold.name);
		System.out.println("bigFold.number="+bigFold.number);
		System.out.println("bigFold.sheep="+bigFold.sheep.getName());
	}
}
测试结果:
小羊圈输出信息如下:
smallFold.name=小羊圈
smallFold.number=10
smallFold.sheep=小羊
大羊圈输出信息如下:
bigFold.name=大羊圈
bigFold.number=100
bigFold.sheep=大羊
 显然,序列化可以实现深度复制的效果,但每个非基本类型对象都必须是可序列化的。而设计模式中的原型啊模式也就是实现深度复制,因此,原型模式可以采用深度复制和序列化两种方式来实现。

       

分享到:
评论

相关推荐

    java面试宝典

    76、什么是java序列化,如何实现java序列化? 18 77、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 18 78、abstract class Name { private String name; public abstract boolean isStupidName...

    java语言程序设计 java编程笔记 由浅入深的笔记 共32份 全套资源.rar

    java序列化.docx Math类.docx Object(对象).docx operator(运算符).docx Properties.docx return语句的例子.docx Scanner和if语法.docx static.docx 毕向东视频的笔记.docx 参数传递.docx 第二周所学总结.docx ...

    java 面试题 总结

    assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为...

    Java核心技术II(第8版)

    1.5.2 修改缺省的序列化机制 1.5.3 序列化单例和类型安全的枚举 1.5.4 版本管理 1.5.5 为克隆使用序列化 1.6 文件管理 1.7 新I/O 1.7.1 内存映射文件 1.7.2 缓冲区数据结构 1.7.3 文件加锁机制 1.8 正则表达式 第十...

    Java面试宝典-经典

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 51 75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的...

    Java面试宝典2010版

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 51 75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的...

    java面试题大全(2012版)

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 51 75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的...

    涵盖了90%以上的面试题

    java序列化 JVM加载class文件的原理 双亲委派模型 为什么要自定义类加载器 如何自定义类加载器 什么是GC 内存泄漏和内存溢出 Java的内存模型(JVM的内存划分) JVM内存模型1.7和1.8的区别 如何判断一个对象是否是垃圾...

    java基础题 很全面

    60. 什么是java序列化,如何实现java序列化? 14 61. 是否可以从一个static方法内部发出对非static方法的调用? 14 62. 写clone()方法时,通常都有一行代码,是什么? 14 63. 在JAVA中,如何跳出当前的多重嵌套循环? 14 64....

    java面试宝典2012版.pdf

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 75、描述一下JVM加载class文件的原理机制? 76、heap和stack有什么区别。 77、GC是什么? 为什么要有GC? 78、垃圾回收的优点和...

    最新Java面试宝典pdf版

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 51 75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的...

    Java面试笔试资料大全

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 51 75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的...

    java面试宝典2012

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 56 75、描述一下JVM加载class文件的原理机制? 56 76、heap和stack有什么区别。 57 77、GC是什么? 为什么要有GC? 57 78、垃圾回收的...

    JAVA面试宝典2010

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 51 75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的...

    Java面试宝典2012新版

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 51 75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾回收的...

    Java面试宝典2012版

    74、什么是java序列化,如何实现java序列化?或者请解释Serializable接口的作用。 51 75、描述一下JVM加载class文件的原理机制? 52 76、heap和stack有什么区别。 52 77、GC是什么? 为什么要有GC? 52 78、垃圾...

    超级有影响力霸气的Java面试题大全文档

    assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为...

Global site tag (gtag.js) - Google Analytics