序列化与对象的克隆

  什么是序列化?以下引用百度百科的解释,我以为是比较恰当的。
 
对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象 将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象,也就是反序列化。

  序列化也叫串行化,譬如我们把对象写到流里,把对象转化为json、xml等都是序列化。这里我们主要讲把对象转为二进制流。

Java序列化实现

   Java中使用 ObjectInputStream 和 ObjectOutputStream 对实现了Serializable接口的对象的进行序列化和反序列化过程。一个类实现了Serializable接口就表示可以被序列化。Serializable接口没有方法,可以看作是一个标记接口。序列化示例代码:

//序列化方法
public static void serial(Object obj)throws IOException
	{
		FileOutputStream fileOutputStream=null;
		ObjectOutputStream objOutputStream=null;
		try
		{
			fileOutputStream=new FileOutputStream("d:\\s.tmp");
			objOutputStream=new ObjectOutputStream(fileOutputStream);
			objOutputStream.writeObject(obj);
		} catch (IOException e)
		{
			throw e;
		}finally{
			if(objOutputStream!=null)objOutputStream.close();
			if(fileOutputStream!=null)fileOutputStream.close();
		}
	}
	//反序列化方法
	public static <T> T deserial(File file)throws IOException,ClassNotFoundException
	{
		FileInputStream fileInputStream=null;
		ObjectInputStream objInputStream=null;
		try
		{
			fileInputStream=new FileInputStream(file);
			objInputStream=new ObjectInputStream(fileInputStream);
			return (T)objInputStream.readObject();
		} catch (IOException e)
		{
			throw e;
		} catch (ClassNotFoundException e)
		{
			throw e;
		}finally{
			if(objInputStream!=null)objInputStream.close();
			if(fileInputStream!=null)fileInputStream.close();
		}
	}
	//调用方法
	public static void main(String[] args)
	{
		Shop tmpShop=new Shop();
		tmpShop.setShopName("商店名");
		tmpShop.setShopNum("001");
		tmpShop.setShopAddress("北京路88号");
		try
		{
			serial(tmpShop);
			Shop newShop=deserial(new File("D:\\s.tmp"));
			System.out.println(newShop.getShopName());//反序列化后比较两个对象
			System.out.println(newShop.equals(tmpShop));//结果false
			System.out.println(newShop==tmpShop);	//结果false
		} catch (IOException e)
		{
			e.printStackTrace();
		} catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}
	}
Java序列化有以下几个特点:
1. 只有实现了 Serializable接口或 Externalizable接口的类才能被序列化, Externalizable继承自 Serializable,可以实现序列化过程的逻辑自定义;

2. 静态变量不会被序列化;

3. Transient修饰的变量不会被序列化;

4. 如果父类没有实现Serializable接口,父类相关内容将不会被序列化,也就意谓着反序列化时父类的变量值将丢失。

5. Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用

可序列化类的版本
  凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量 private static final long serialVersionUID,默认serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。当版本标识不一样时,即时类的代码完全一样反序列化也会失败。
  如果不在代码中显式定义这个值,则Java会提供默认实现,对类的源代码作了修改再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化,而不同虚拟机的实现也有可能是不同的,所以建议显式的定义该值。

对象的克隆
  对象的克隆也叫复制,分为浅复制和深复制。浅复制复制出来的对象的所有变量与原对象相同,而所有对其他对象的引用仍然指向原对象。而深复制自然是连引用对象也复制了一份出来了。
Java中浅复制实现就简单,Object类提供了Clone()方法,代码如下:

public class Entity implements Cloneable
{
	private String name;
	private String age;
	private Shop shop;
	public Object clone()
	{
		try
		{
			return super.clone();
		} catch (CloneNotSupportedException e)
		{
			return null;
		}
	}
}
Cloneable接口是个标记类,告诉java虚拟机该类可以使用安全使用clone方法,如果类未实现Cloneable接口调用clone方法就会抛出CloneNotSupportedException异常。

那么深复制是如何实现的呢?这里就要用到前面提到的序列化了。思路就是序列化一个对象到临时内存中,然后再反序列化生成一个新对象。

public class Entity implements Cloneable,Serializable
{
	private String name;
	private int age;
	private Shop shop;//一个引用类型成员变量
	public Shop getShop()
	{
		return shop;
	}

	public void setShop(Shop shop)
	{
		this.shop = shop;
	}

	public String getName()
	{
		return name;
	}

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

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}
	//浅复制
	public Object clone()
	{
		try
		{
			return super.clone();
		} catch (CloneNotSupportedException e)
		{
			return null;
		}
	}
	//序列化实现深复制
	public Object deepClone()throws IOException, ClassNotFoundException
	{
		//序列化本身
		ByteArrayOutputStream byteOutStream=new ByteArrayOutputStream();
		ObjectOutputStream objOutStream=new ObjectOutputStream(byteOutStream);
		objOutStream.writeObject(this);
		//反序列化生成新对象
		ByteArrayInputStream byteInStream=new ByteArrayInputStream(byteOutStream.toByteArray());
		ObjectInputStream objInStream=new ObjectInputStream(byteInStream);
		return objInStream.readObject();
	}
	
	public static void main(String[] args)throws Exception
	{
		Entity e1=new Entity();
		e1.setName("charles");
		e1.setAge(18);
		e1.setShop(new Shop("001","shop1"));
		Entity e2=(Entity)e1.clone();
		Entity e3=(Entity)e1.deepClone();
		System.out.println(e1.getShop().equals(e2.getShop()));//结果输出true
		System.out.println(e1.getShop().equals(e3.getShop()));//结果输出false
		
	}
}


你可能感兴趣的:(java序列化,序列化,深复制,Java克隆)