首先Java中的序列化和反序列化功能应用非常普遍,回想在本科刚接触Java这门课程的时候就已经知道这个概念了,但是具体是什么含义,什么原理从没关注过,“能用就行”这是当时的想法。现在随着学习、工作也逐渐认识到技术本质的重要性,所以写下这么一篇总结性的文章。
Java序列化的定义
将那些实现了serializable接口的对象转化成一个字节序列(内存中的状态),并能够在以后将这个字节序列恢复成原来的对象,主要用于弥补不同操作系统之间的差异,解决不同操作系统之间对象的传输问题。
Java序列化的应用场景
- Java远程方法调用(RMI)
- 用socket在网络上传输对象
- 对内存中的JavaBean进行实例化到文件或者DB中
如何实现序列化和反序列化
序列化过程
1、实现Serializable接口
- 该接口只是一个可序列化的标志,并没有包含实际的属性和方法。
- 若不再该实现中添加readObject()和writeObject()方法,则采用默认的序列化机制,如果添加了上述两个方法后,仍然想采用默认的序列化机制,就需要在上述两个方法中分别调用defaultReadObject()和defaultWriteObject()两个方法。
- 为了保证安全性,可以使用transient关键字来修饰不需要序列化的属性。
2、实现Externalizable接口
- 完全由类本事来对需要序列化的内容进行控制,控制哪些属性需要序列化,哪些不需要。
反序列化过程
- 实现Serializable接口的对象在反序列化过程中不需要调用对象所在类的构造方法,完全基于字节。
- 实现了Externalizable接口的对象在反序列化过程中回调用不带参数的构造方法,若不存在该构造函数,或该构造函数为private或protected级别,则会抛出异常。
使用时注意事项
- 被static修饰的属性不会被序列化。
- 对象的类名、属性都会被序列化,方法不会被序列化。
- 要保证序列化对象所在类的属性(特别是属性是对象的情况)也是可以被序列化的。
- 当通过网络或者文件进行序列化的时候,必须按照写入的顺序读取对象。
- 反序列化的时候必须有序列化对象的class文件
- 最好显式的声明serializableID,因为在不同的JVM之间,默认生成的serializableID不同,会造成反序列化过程的失败。
- 当父类继承Serializable接口,则所有的子类都可以被序列化。
- 子类实现了Serializable接口,但父类没有,则父类中的属性不能序列化(不报错,但数据会丢失),但子类中属性均能正常序列化。
- 在反序列化过程中,如果对象的属性有修改或者删减,则修改的部分属性会丢失,但是不会报错。
常见的序列化协议
- COM
- CORBA
- XML&SOAP
- JSON
- Thrift
- Protobuf
- Avro
针对以上罗列的系列化协议,除了比较老的COM和CORBA等,各有优势,感兴趣可详细了解一下。