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

41、对象序列化与反序列化

2017年11月28日 ⁄ 综合 ⁄ 共 3042字 ⁄ 字号 评论关闭

      将对象转换为节流保存起来,并在以后还原这个对象,这种机制叫做对象序列化。
      将一个对象保存到永久存储设备上称为持久化。
      一个对象要想能够实现序列化,必须实现Serializable接口或Externalizable接口。

1、Serializable是一个接口,并且没有定义方法。一个类如想被序列化,则需要实现java.io.Serializable接口,该接口中没有定义任何方法,是一个标识性接口(marker Interface),当一个类实现了该接口,就表示这个类的对象是可以序列化的。

      序列化(serialization)是把一个对象的状态写入一个字节流的过程。当你想要把你的程序状态存到一个固定的存储区域例如文件时,它是很管用的。稍后一点时间,你就可以运用序列化过程存储这些对象

      假设一个被序列化的对象引用了其他对象,同样,其他对象又引用了更多的对象。这一系列的对象和它们的关系形成了一个顺序图表。在这个对象图表中也有循环引用。也就是说,对象X可以含有一个对象Y的引用,对象Y同样可以包含一个对象X的引用。对象同样可以包含它们自己的引用。对象序列化和反序列化的工具被设计出来并在这一假定条件下运行良好。如果你试图序列化一个对象图表中顶层的对象,所有的其他的引用对象都被循环的定位和序列化。同样,在反序列化过程中,所有的这些对象以及它们的引用都被正确的恢复

2、当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量。
      如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
      如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化

      总结:在序列化时,static变量是无法序列化的;如果A包含了对B的引用,那么在序列化A的时候也会将B一并序列化;如果此时A可以序列化,B无法序列化,那么当序列化A的时候就会发生异常,这时就需要将对B的引用设置为transient,该关键字表示变量不会被序列化。

3、Serializable接口
      –只有一个实现Serializable接口的对象可以被序列化工具存储和恢复。Serializable接口没有定义任何成员。它只用来表示一个类可以被序列化。如果一个类可以序列化,它的所有子类都可以序列化。
      –声明成transient的变量不被序列化工具存储。同样,static变量也不被存储

4、ObjectOutput接口
      –ObjectOutput 继承DataOutput接口并且支持对象序列化。特别注意writeObject( )方法,它被称为序列化一个对象。所有这些方法在出错情况下引发IOException 异常

5、ObjectOutputStream类
      –ObjectOutputStream类继承OutputStream 类和实现ObjectOutput 接口。它负责向流写入对象。该类的构造方法如下:
      –ObjectOutputStream(OutputStream outStream) throws IOException
      –参数outStream 是序列化的对象将要写入的输出流

6、ObjectInput
      –ObjectInput 接口继承DataInput接口。它支持对象序列化。特别注意 readObject( )方法,它叫反序列化对象。所有这些方法在出错情况下引发IOException 异常

7、ObjectInputStream
      –ObjectInputStream 继承InputStream 类并实现ObjectInput 接口。ObjectInputStream 负责从流中读取对象。该类的构造方法如下:
      –ObjectInputStream(InputStream inStream) throws IOException,StreamCorruptedException
      –参数inStream 是序列化对象将被读取的输入流。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerialzableTest1
{
	public static void main(String[] args) throws Exception
	{
		Person2 p1 = new Person2(20,"zhang",44.23);
		Person2 p2 = new Person2(30,"li",43.45);
		Person2 p3 = new Person2(40,"wang",43.09);
		
		FileOutputStream fos = new FileOutputStream("Person.txt");
		
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		
		oos.writeObject(p1);
		oos.writeObject(p2);
		oos.writeObject(p3);
		oos.close();
		FileInputStream fis = new FileInputStream("Person.txt");
		ObjectInputStream ois = new ObjectInputStream(fis);
		
		Person2 p = null;
		
		for(int i = 0; i<3;i++)
		{
			p =(Person2)ois.readObject();
			System.out.println(p.age + ":" + p.name + ":" + p.height);
		}
		
		ois.close();
	}
}
class Person2 implements Serializable
{
	int age;
	transient String name;
	double height;
	public Person2(int age, String name, double height)
	{
		this.age = age;
		this.name = name;
		this.height = height;
	}
	
}

8、在序列化和反序列化进程中需要特殊处理的 Serializable 类应该实现以下方法:

      private void writeObject(java.io.ObjectOutputStream stream)  throws IOException;
      private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException;
      这两个方法不属于任何一个类和任何一个接口,是非常特殊的方法.

当我们在一个待序列化、反序列化的类中实现了以上两个private方法(方法声明要与上面的保持完全的一致),那么就允许我们以更加底层、更加细粒度化的方式控制序列化、反序列化的过程。(也就是说写哪些属性,读哪些属性都由这两个方法来确定)

抱歉!评论已关闭.