现在的位置: 首页 > 综合 > 正文

Java的序列化、反序列化

2013年11月30日 ⁄ 综合 ⁄ 共 5405字 ⁄ 字号 评论关闭
  • 序列化的适用场景
1、永久性保存对象,保存对象的字节序列到本地文件中; 
2、通过序列化对象在网络中传递对象,套接字在网络上传送对象的时候;

3、通过序列化在进程间传递对象;

4、当你想通过RMI传输对象的时候。
  • 序列化介绍
1、对象序列化(Serializable)是指将对象转换为流的过程,而反序列化则是根据流恢复对象的过程。
2、对象所属的类必须实现Serializable或是Externalizable接口才能被序列化。对实现了Serializable接口的类,其序列化与反序列化采用默认的序列化方式,Externalizable接口是继承了Serializable接口的接口,是对Serializable的扩展,实现了Externalizable接口的类完全自己控制序列化与反序列化行为。

Java.io.ObjectOutputStream代表对象输出流,其方法writeObject(Object obj)可以实现对象的序列化,将得到的字节序列写到目标输出流中。Java.io.ObjectInputStream代表对象输入流,其readObject()方法能从源输入流中读取字节序列,将其反序列化为对象,并将其返回。
  • 序列化对象的内容
在序列化对象的时候,序列化的内容是:
1)对象的类型 
2)对象属性的类型 
3)对象属性的值 

  • 序列化的几种方式
以对象Person为例:
1、实现Serializable,未定义readObject和writeObject方法。
ObjectOutputStream使用JDK默认方式对Person对象的非transient的实例变量进行序列化;
ObjectInputStream使用JDK默认方式对Person对象的非transient的实例变量进行反序列化。
范例:
package advanceBase;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;

public class SerializationDemo implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private int uid;
	public String Name;
	private int age;
	public String phone;
	private String adr;

	public int getUid() {
		return uid;
	}

	public void setUid(int uid) {
		this.uid = uid;
	}

	public String getName() {
		return Name;
	}

	public void setName(String name) {
		Name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getAdr() {
		return adr;
	}

	public void setAdr(String adr) {
		this.adr = adr;
	}

	/**
	 * @param args
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public static void main(String[] args) throws IOException,
			ClassNotFoundException {

		SerializationDemo sd = new SerializationDemo();
		sd.setUid(1);
		sd.setName("Bruce");
		sd.setAge(26);
		sd.setPhone("18600009898");
		sd.setAdr("世界之窗");

		// 序列化
		OutputStream fos = new FileOutputStream("c:/sdTest.txt");
		// FileOutputStream fos=new FileOutputStream("c:/sdTest.txt");
		ObjectOutputStream os = new ObjectOutputStream(fos);
		os.writeObject(sd);
		os.close();
		fos.close();

		// 反序列化
		InputStream fis = new FileInputStream("c:/sdTest.txt");
		// FileInputStream fis=new FileInputStream("c:/sdiTest.txt");
		ObjectInputStream ois = new ObjectInputStream(fis);
		SerializationDemo _sd = (SerializationDemo) ois
				.readObject();
		ois.close();
		fis.close();
		System.out.println("Name:" + _sd.getName());

	}

}

//输出:
Name:Bruce

 
2、 实现Serializable,并定义了readObject和writeObject方法
ObjectOutputStream调用Customer类的writeObject(ObjectOutputStream out)方法对Person对象的非transient的实例变量进行序列化;
ObjectInputStream调用Customer类的readObject(ObjectInputStream in)方法对Person对象的非transient的实例变量进行反序列化。 


3、实现Externalizable,定义readExternal和writeExternal方法
ObjectOutputStream调用Customer类的writeExternal方法对Customer对象的非transient实例变量进行序列化;
ObjectInputStream首先通过Customer类的无参数构造函数实例化一个对象,再用readExternal方法对Customer对象的非transient实例变量进行反序列化。 

范例:
package advanceBase;

import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.Date;

public class ExternalizableDemo implements Externalizable {

	private int uid;
	public String Name;
	private int age;
	public String phone;
	private String adr;

	public int getUid() {
		return uid;
	}

	public void setUid(int uid) {
		this.uid = uid;
	}

	public String getName() {
		return Name;
	}

	public void setName(String name) {
		Name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getAdr() {
		return adr;
	}

	public void setAdr(String adr) {
		this.adr = adr;
	}

	@Override
	public void writeExternal(ObjectOutput out) throws IOException {
		System.out.println("序列化...");
		Date date = new Date();
		System.out.println(date);
		// 序列化其它的类的实例
		out.writeObject(date);
		// 序列化两个属性
		out.writeObject(Name);
		out.writeObject(phone);

	}

	@Override
	public void readExternal(ObjectInput in) throws IOException,
			ClassNotFoundException {
		System.out.println("反序列化...");
		// 反序列化Date实例
		Date date = (Date) in.readObject();
		System.out.println(date);
		// 反序列化两个属性
		this.Name = (String) in.readObject();
		this.phone = (String) in.readObject();

	}

	/**
	 * @param args
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public static void main(String[] args) throws IOException,
			ClassNotFoundException {
		ExternalizableDemo ed= new ExternalizableDemo();
		ed.setName("bruce");
		ed.setPhone("18600009988");
		ed.setAge(26);

		// 序列化
		FileOutputStream fos = new FileOutputStream("c:/ed.txt");
		ObjectOutputStream os = new ObjectOutputStream(fos);
		os.writeObject(ed);
		os.close();
		fos.close();

		// 反序列化
		FileInputStream fis = new FileInputStream("c:/ed.txt");
		ObjectInputStream ois = new ObjectInputStream(fis);
		ExternalizableDemo _ed = (ExternalizableDemo) ois
				.readObject();
		ois.close();
		fis.close();
		System.out.println("Name:" + _ed.Name);
		System.out.println("phone:" + _ed.phone);
		System.out.println("age:" + _ed.age);

	}

}

//输出:


序列化...
Sun Apr 22 21:35:54 CST 2012
反序列化...
Sun Apr 22 21:35:54 CST 2012
Name:bruce
phone:18600009988
age:0

//date被序列化,age没有被序列化

扩展了解:
#以下总结~转#
如果采用默认的序列化方式,只要让一个类实现Serializable接口,其实例就可以被序列化。通常,专门为继承而设计的类应该尽量不要实现Serializable接口,因为一旦父类实现了Serializable接口,其所有子类也都是可序列化的了。

默认的序列化方式的不足之处:

1.直接对对象的不宜对外公开的敏感数据进行序列化,这是不安全的;
2.不会检查对象的成员变量是否符合正确的约束条件,有可能被传改数据而导致运行异常;
3.需要对对象图做递归遍历,如果对象图很复杂,会消耗很多资源,设置引起Java虚拟机的堆栈溢出;
4.使类的接口被类的内部实现约束,制约类的升级与维护。

通过实现Serializable接口的private类型的writeObject()和readObject(),或是实现Externalizable接口,并实现writeExternal()与readExternal()方法,并提供public类型的无参数构造函数两种方式来控制序列化过程可以有效规避默认序列化方式的不足之处。


抱歉!评论已关闭.