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序列化的机制和原理 有关Java对象的序列化和反序列化也算是Java基础的一部分,下面对Java序列化的机制和原理进行一些介绍。 Java序列化算法透析 Serialization...
  • js_gary
  • js_gary
  • 2012年01月09日 16:34
  • 5689

Java 和 Hadoop 序列化机制浅讲

序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程(字节流)。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状...
  • zq602316498
  • zq602316498
  • 2015年04月22日 11:42
  • 1124

Hadoop序列化机制及实例

序列化1、什么是序列化? 将结构化对象转换成字节流以便于进行网络传输或写入持久存储的过程。 2、什么是反序列化? 将字节流转换为一系列结构化对象的过程。序列化用途:1、作为一种持久化格式。 2...
  • scgaliguodong123_
  • scgaliguodong123_
  • 2015年06月10日 22:37
  • 2974

Java序列化与反序列化 & 深拷贝

package com.main.domain; public enum Gender { // 枚举类型都会默认继承类java.lang.Enum,而该类实现了Serializable接口,所以枚...
  • LuckyBug007
  • LuckyBug007
  • 2017年04月12日 20:02
  • 542

spark性能调优之使用Kryo序列化

在SparkConf中设置一个属性,spark.serializer,org.apache.spark.serializer.KryoSerializer类;注册你使用到的,需要通过Kryo序列化的,...
  • hutao_hadoop
  • hutao_hadoop
  • 2016年09月28日 21:58
  • 1516

jackson的序列化和反序列化的实现

Java下常见的Json类库有Gson、JSON-lib和Jackson等,Jackson相对来说比较高效,在项目中主要使用Jackson进行JSON和Java对象转换,下面给出一些Jackson的J...
  • LanSeTianKong12
  • LanSeTianKong12
  • 2016年09月08日 15:33
  • 733

java中的序列化(Serializable)和反序列化

JAVA序列化与反序列化就是JAVA对象与一串字节流之间的相互转换, 我们在程序中创建的JAVA对象只存在于JVM中, 当程序退出时, 这些对象也就消失了, 而序列化正是为了将这些对象保存起来以仅将来...
  • jason_279
  • jason_279
  • 2016年10月27日 16:37
  • 4306

JAVA序列化机制的深入研究

1、java序列化简介 序列化就是指对象通过写出描述自己状态的数值来记录自己的过程,即将对象表示成一系列有序字节,java提供了将对象写入流和从流中恢复对象的方法。对象能包含其它的对象,而其它的对象...
  • gulianchao
  • gulianchao
  • 2015年06月07日 09:53
  • 1582

java序列化与反序列化(2)------jdk原生序列化机制Serializable

使用jdk原生的序列化机制,我们要把需要序列化的类实现Serializable接口,这是一个标记接口没有声明任何的方法。...
  • u011784767
  • u011784767
  • 2017年10月03日 21:13
  • 515

java序列化与反序列化(3)------jdk原生序列化机制Externalizable

我们在上一篇博客中介绍了类实现标记性接口Serializable来实现序列化,但是如果你只想序列化诸多域中的某几个域,一种选择是将不序列化的域都标记上transient关键字,但是如果不需要序列化的域...
  • u011784767
  • u011784767
  • 2017年10月05日 16:46
  • 490
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java序列化与反序列化(4)------jdk原生序列化机制实现深拷贝
举报原因:
原因补充:

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