东风恶、欢情薄,一怀愁绪,几年离索。错!错!错!
——陆游《钗头凤》
IO流之序列化流
1. 概述
Java 提供了一种对象序列化的机制。用一个字节序列
可以表示一个对象,该字节序列包含该 对象的数据 、 对象的类型 和 对象中存储的数据 等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。 对象的数据 、 对象的类型 和 对象中存储的数据 信息,都可以用来在内存中创建对象。
看图理解序列化
2. ObjectOutputStream
类
java.io.ObjectOutputStream
类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。序列化对象。
构造方法
public ObjectOutputStream(OutputStream out)
: 创建一个指定OutputStream的ObjectOutputStream
。构造举例,代码如下:
1
2
3 FileOutputStream fileOut = new FileOutputStream("employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
序列化操作
一个对象要想序列化,必须满足两个条件:
- 该类必须实现
java.io.Serializable
接口,Serializable
是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException
。serialVersionUID
:序列化的版本号,凡是实现 Serializable 接口的类都有一个静态的表示序列化版本标识符的变量。
- 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用
transient
关键字修饰。
1 | public class Employee implements java.io.Serializable { |
写出对象方法
public final void writeObject (Object obj) ;
将指定的对象写出。
1 | public class SerializeDemo{ |
3. ObjectInputStream
类
ObjectInputStream
反序列化流,将之前使用ObjectOutputStream
序列化的原始数据恢复为对象。
构造方法
public ObjectInputStream(InputStream in)
: 创建一个指定InputStream
的ObjectInputStream
。
反序列化操作
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用
ObjectInputStream
读取对象的方法.
public final Object readObject () ; 读
取一个对象。
1 | public class DeserializeDemo { |
反序列化操作–显式添加序列版本号
JDK1.8 API的解读
序列化运行时将每个可序列化的类与称为
serialVersionUID
的版本号相关联,该序列号在反序列化期间用于验证序列化对象的发送者和接收者是否已加载与该序列化兼容的对象的类。
如果接收方加载了一个具有不同于相应发件人类的serialVersionUID
的对象的类,则反序列化将导致InvalidClassException
。 一个可序列化的类可以通过声明一个名为"serialVersionUID"
的字段来显式地声明它自己的serialVersionUID
,该字段必须是静态的,最终的,类型是long
1 ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;如果可序列化类
没有显式声明serialVersionUID
,则序列化运行时将根据Java(TM)对象序列化规范中所述的类的各个方面计算该类的默认serialVersionUID值。但是,强烈建议所有可序列化的类都明确声明serialVersionUID值,因为默认的serialVersionUID计算对类详细信息非常敏感,这可能会因编译器实现而异,因此可能会在反InvalidClassException
化期间导致InvalidClassException
的InvalidClassException
。因此,为了保证不同Java编译器实现之间的一致的serialVersionUID值,一个可序列化的类必须声明一个显式的serialVersionUID值。还强烈建议,显式的serialVersionUID声明在可能的情况下使用
private
修饰符,因为这种声明仅适用于立即声明的类 - serialVersionUID字段作为继承成员无效。数组类不能声明一个显式的serialVersionUID,所以它们总是具有默认的计算值,但是对于数组类,放弃了匹配serialVersionUID值的要求。
1 | public class Employee implements java.io.Serializable { |
4. 练习–序列化集合
将存有多个自定义对象的集合序列化操作,保存到 list.txt 文件中。
反序列化 list.txt ,并遍历集合,打印对象信息。
案例分析
把若干学习对象 ,保存到集合中。
把集合序列化。
反序列化读取时,只需要读取一次,转换为集合类型。
遍历集合,可以打印所有的学生信息
案例实现
1 | public class SerTest { |