java序列化与反序列化(4)------jdk原生序列化机制实现深拷贝

原创 2017年10月06日 15:57:24

简单地说所谓深拷贝就是将对象域为引用指向的内存中对象,在内存中再创建一份赋值给深拷贝出的新对象。

(1) 实现Cloneable接口的深拷贝

我们先看之前执行深拷贝的方法,直接上代码:

/**
 * 实现Cloneable接口,并重写clone方法
 * @author yujie.wang3
 *
 */
public class Book implements Cloneable{
	private int page;
	
	private String name;
	
	private Owner owner;

	public Book(){
		System.out.println("invoke Book()");
	}
	public Book(int page, String name, Owner owner) {
		this.page = page;
		this.name = name;
		this.owner = owner;
		System.out.println("invoke Book(int page, String name, Owner owner)");
	}

	public Owner getOwner() {
		return owner;
	}

	public void setOwner(Owner owner) {
		this.owner = owner;
	}

	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public String getName() {
		return name;
	}

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

	/**
	 * 这里执行深拷贝
	 */
	@Override
	public Object clone()  {
		// TODO Auto-generated method stub
		Book b = null;
		try {
			b = (Book)super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		b.owner = (Owner)owner.clone();
		return b;
	}
}


/**
 * 实现Cloneable接口,并重写clone方法
 * @author yujie.wang
 *
 */
public class Owner implements Cloneable{
	private int age;
	
	private String name;
	
	public Owner(){
		System.out.println("invoke Owner()");
	}

	public Owner(int age, String name) {
		this.age = age;
		this.name = name;
		System.out.println("Owner(int age, String name)");
	}

	/**
	 * 这里执行克隆拷贝
	 */
	@Override
	public Object clone(){
		// TODO Auto-generated method stub
		Owner owner = null;
		try {
			owner = (Owner)super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return owner;
	}

	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
	public String toString() {
		return "Owner [age=" + age + ", name=" + name + "]";
	}
	
}

测试代码如下:

/**
 * 深拷贝测试类
 * @author yujie.wang
 *
 */
public class Test {
	public static void main(String [] args){
		Owner owner = new Owner(20,"yujie");
		Book b1 = new Book(100,"thinking in java",owner);
		// b1执行深拷贝给b2,其中b2中owner域为新的对象不同于上面那个owner的指向
		Book b2 = (Book)b1.clone();
		System.out.println(b1.getName() + " " + b1.getPage() + " " + b1.getOwner().toString());
		System.out.println(b2.getName() + " " + b2.getPage() + " " + b2.getOwner().toString());
		b1.setName("network");
		b1.setPage(200);
		// 这里b1的owner指向的对象状态发生改变,但是不影响b2中owner域
		owner.setAge(22);
		owner.setName("kobe");
		System.out.println(b1.getName() + " " + b1.getPage() + " " + b1.getOwner().toString());
		System.out.println(b2.getName() + " "  + b2.getPage() + " " + b2.getOwner().toString());
	}

}

运行测试代码输出结果如下:

Owner(int age, String name)
invoke Book(int page, String name, Owner owner)
thinking in java 100 Owner [age=20, name=yujie]
thinking in java 100 Owner [age=20, name=yujie]
network 200 Owner [age=22, name=kobe]
thinking in java 100 Owner [age=20, name=yujie]

从输出结果中我们看到b1的owner引用内容修改之后并没有影响b2的owner域,这说明深拷贝成功。

当然有一个现象就是,在执行深拷贝创建一个新对象的时候并没有调用任何构造函数。


(2)实现Serializable,Cloneable接口的深拷贝

如果需要执行深拷贝的类中有大量的引用存在,那么需要对每个引用都要实现Cloneable接口并重写clone方法,这看起来是一个十分繁琐的事情,当然其实还有一种方法比较简便就是使用序列化机制来实现深拷贝。

我们改造上面的代码:

/**
 * 实现Serializable,Cloneable接口,并重写clone方法
 * @author yujie.wang3
 *
 */
public class Book implements Serializable,Cloneable{
	private int page;
	
	private String name;
	
	private Owner owner;

	public Book(){
		System.out.println("invoke Book()");
	}
	public Book(int page, String name, Owner owner) {
		this.page = page;
		this.name = name;
		this.owner = owner;
		System.out.println("invoke Book(int page, String name, Owner owner)");
	}

	public Owner getOwner() {
		return owner;
	}

	public void setOwner(Owner owner) {
		this.owner = owner;
	}

	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public String getName() {
		return name;
	}

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

	/**
	 * 这里通过序列化执行深拷贝
	 */
	@Override
	public Object clone()  {
		// TODO Auto-generated method stub
		Object o = null;
		try {
			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			ObjectOutputStream 	out = new ObjectOutputStream(bout);
			out.writeObject(this);
			out.close();
			ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
			ObjectInputStream in = new ObjectInputStream(bin);
			o = in.readObject();
			in.close();
			bin.close();
			bout.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return o;
	}
}

/**
 * 实现Serializable标记接口
 * @author yujie.wang
 *
 */
public class Owner implements Serializable{
	private int age;
	
	private String name;
	
	public Owner(){
		System.out.println("invoke Owner()");
	}

	public Owner(int age, String name) {
		this.age = age;
		this.name = name;
		System.out.println("Owner(int age, 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
	public String toString() {
		return "Owner [age=" + age + ", name=" + name + "]";
	}
	
}


测试类不用改变,运行测试代码输出如下结果:

Owner(int age, String name)
invoke Book(int page, String name, Owner owner)
thinking in java 100 Owner [age=20, name=yujie]
thinking in java 100 Owner [age=20, name=yujie]
network 200 Owner [age=22, name=kobe]
thinking in java 100 Owner [age=20, name=yujie]

这个输出结果和第一种方式一样,但是同样有一个现象就是通过序列化机制创建对象的时候也没有调用任何构造函数。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

java提高篇-----使用序列化实现对象的拷贝 (深拷贝)

我们知道在Java中存在这个接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性能的提升非常...
  • yuj9006
  • yuj9006
  • 2013年10月23日 20:59
  • 490

Java 深拷贝ArrayList实例(包括递归和序列化方法)

 前言:       日前一哥们问我一个有关多层ArrayList拷贝的问题,我帮他写了一个例程,感觉以后用得着,便放上来了。如果要在自身类中加入Clone功能,需要implements IClone...

spring-data-redis 整合,以及使用kryo序列化代替jdk原生序列化机制

之前一直没使用spring-data-redis模板进行redis操作,周日闲着没事,整合了下,又想不适用jdk原生的序列化,于是自己简单的,参考网上的,后期路过的坑,修改了下, 引入 spring-...

C#通过序列化实现深拷贝

关于浅拷贝和深拷贝,我的理解不是很清晰,简单说来,我认为是这样子:   浅拷贝:引用成员在被拷贝时仅复制源对象中引用成员的地址到新对象中,所以在新对象中对引用成员进行更改会影响到源对象(除对引用...
  • lnc2003
  • lnc2003
  • 2014年12月31日 10:37
  • 355

通过序列化实现深拷贝

import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOExceptio...

PHP 中 Session 反序列化机制

简介 在php.ini中存在三项配置项: session.save_path=""   --设置session的存储路径 session.save_handler="" --设定用...

Java 浅拷贝、深拷贝与序列化

深拷贝(deep clone)与浅拷贝(shallow clone)   浅拷贝(浅复制、浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。  ...

Java序列化技术性能分析(JDK原生与Protostuff)

熟悉Java的朋友应该知道Java有一个叫序列化的技术,即把一个Object转换为可保存,可传输的流数据。相应的,同时存在反序列化,即将流数据转换为Object类,而在转换的过程中,该Object保持...
  • canot
  • canot
  • 2016年12月19日 23:33
  • 3471

java反序列化利用

  • 2017年08月31日 23:54
  • 33.79MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java序列化与反序列化(4)------jdk原生序列化机制实现深拷贝
举报原因:
原因补充:

(最多只允许输入30个字)