常见实例场景
- 在网络通信中:发送数据之前要序列化:send()->原始数据->序列化数据->TCP缓冲区,反之为反序列化,接收数据时候做的。
- Tomcat中,在服务正常关闭时候,会将session对象序列化到SESSIONS.ser文件中,下次启动重新加载到内存中
- Socket套接字通信中,对象在客户端与服务端传输也是通过序列化和反序列化。
使用场景
- 对象数据的持久化,因为字节序列可以比较方便地存储
- 在网络中序列化的字节流方便传递和接收,可以实现远程通信
- 在进程间通过序列化传递对象
- 主要是为了保存在内存中的各种对象的状态(不管成员方法),然后反序列化就是读取那些状态重做一个实例对象(有点像《三体》中三体人的脱水和复活)
序列化机制
Serializable接口
ObjectOutputStream.writeObject(object)
ObjectInputStream.readObject(object)
要保存到文件中的话ObjectOutputStream os = new ObjectOutputStream(FileOutputStream)
Externalizable接口
继承自Serializable接口
需要重写writeExternal&readExternal,用于个性化定制
需要提供一个public的无参构造器
进一步的认识
serialVersionUID
对序列化的对象进行版本控制,一组序列化与反序列化需要保持此值一只才能正确进行,当新类型与旧数据不兼容时,即更新版本号。
默认为“1L”,也可以根据类名、接口、方法以及属性生成一个64位的哈希字段“xxxxL”
官方文档强烈建议所有可序列化类都显式声明此值,并且使用private修饰此变量
静态变量的序列化
静态变量不会被序列化,因为在全局,流中没有写入静态变量。
transient关键字
可以控制变量序列化,在声明时加上此关键字,变量就不能被序列化到文件中,此时如果被序列化再反序列化,就会出现该变量类型的初始值,能够保障数据的安全。
序列化实现深克隆
序列化之后read出来,赋值给新的实例。
集合类的序列化
很多都在源码中重写了序列化的方法,并非完全保存了原来的集合状态,例如ArrayList的序列化和反序列话会根据集合中实际存储的元素个数操作,因为扩容机制决定了基本上容量是超出实际存储的。
重写方法
在序列化和反序列化过程中需要特殊处理的类必须使用三个方法的准确签名来实现特殊的方法
对象序列化的持久存储与保存到数据库的持久化
保存到数据库称为对象关系的映射,是将内存对象与真实数据库表中的数据进行映射绑定,而不是直接对实例对象进行了什么保存操作;序列化是对象的脱水和深拷贝。
Tips
- 父类实现序列化接口则子类自动也实现
- 对象的实例变量引用其他的对象,则被引用的对象也会被序列化
- 对于有的对象有private的域,如果进行了序列化,那么private域就不受保护了
- 资源分配相关的类实例,如socket,thread等,即使进行序列化,也不会将资源分配保存下来,咩有序列化的意义
Reference
https://www.cnblogs.com/chenbenbuyi/p/10741195.html
https://www.iteye.com/blog/xiebh-121311
https://baijiahao.baidu.com/s?id=1636492159314232573&wfr=spider&for=pc
https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html