对象序列化保存对象的“状态”,也就是成员变量,不会关注类中的静态变量和方法。如果对象的成员是对象则递归处理。
1. 使用场景
- 将内存中的对象状态保存到文件或数据库;
- 在网络上用socket传输对象;
- 通过RMI传输对象。
2. Serializable
接口
- 任何需要被序列化的对象都需要实现此接口,此接口完全为空,只用来说明此接口实现类的对象可以被序列化。
- 如果父类实现此接口,子类自动可序列化,不用显示实现此接口;
- 如果子类实现而父类没实现,那么父类必须有无参构造方法(如果自定义了有参构造函数,就必须写出无参构造函数;都没有时默认生成无参构造函数),此时反序列化得到的对象的父类变量可能和当前的父类变量不同。
String
、Enum
、数组
可序列化,此外必须实现了此接口,才可序列化。
3. 对象读写
序列化工作通过ObjectOutputStream
和ObjectInputStream
来完成的,使用writeObject
和readObject
对对象进行读写,对于基本类型,可采用readInt
|weiteInt
等接口读写。
4. transient
关键字
修饰类的变量使得序列化过程忽略该变量(修饰static
变量不报错,没意义),此关键字标识的引用会以null
返回,基本类型以对应的默认值返回。
5. serialVersionUID
Java序列化机制通过serialVersionUID
判断类的版本一致性,同样的类如果serialVersionUID
不同不能互相反序列化。InvalidClassException
。
6. 存储规则
- 同一个对象多次存入一个文件,只是多存储一份引用;
- 修改后的对象存入同一个文件,判断文件中已有该对象,后面只存储引用,依次读出的对象都是第一次的对象,没有修改的值。
writeObject
和readObject
1 | private void writeObject(ObjectOutputStream out){ |
- 序列化类定义这两个方法必须是
private
(使用反射调用的)。 writeInt
是将area
单独保存到文件,而非保存成对象的属性,readInt
是单独读取并设置成属性。- 序列化对象时,如果对象有
writeObject
方法,则调用,否则执行默认序列化规则;反序列化同理。
7. Externalizable
接口
Externalizable
继承于Serializable
,当使用该接口时,序列化的细节需要由程序员去完成。
- 实现
writeExternal
和readExternal
方法 - 序列化类必须有
public
无参构造函数(readExternal
先调用无参构造函数创建对象,再自行赋值) - 生成文件存储格式和
Serializable
不太相同
8. readResolve()
用于解决反序列化后违背单例的问题。
无论是实现Serializable
接口,或是Externalizable
接口,当从I/O
流中读取对象时,readResolve()
方法都会被调用到。实际上就是用readResolve()
中返回的对象直接替换在反序列化过程中创建的对象。
测试发现,使用``Externalizable时,此方法
readExternal之后调用;使用
Serializable时,也是在
readObject`之后调用。
9. 缺点
- 无法跨语言
- 序列化后的码流较大
- 序列化性能较低
赏
使用支付宝打赏
使用微信打赏
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章