java 序列化 场景_Java 序列化 - 半路老王的架构师之路 - OSCHINA - 中文开源技术交流社区...

概念

序列化:将对象写入到 IO 流中

反序列化:从 IO 流中恢复对象。反序列化并不会调用构造方法。反序列的对象是由JVM自己生成的对象,不通过构造方法生成。

序列化的意义:序列化机制允许将实现序列化的 Java 对象转换为字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象的目的。序列化机制使得对象可以脱离程序的运行而独立存在。

使用场景:所有可在网络上传输的对象都必须是可序列化的,比如 RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的 Java 对象都必须是可序列化的。

开发建议:程序创建的每个JavaBean 类都实现 Serializeable 接口。

注意:序列化对象保存的是对象的“状态”,即他的成员变量,但不会保存静态变量。

序列化算法

所有保存到磁盘的对象都有一个序列化编码号

当程序试图序列化一个对象时,会先检查此对象是否已经序列化过,只有此对象从未(在此虚拟机)被序列化过,才会将此对象序列化为字节序列输出。

如果此对象已经序列化过,则直接输出编号即可。

Transient

使用 transient 修饰的属性,java序列化时,会忽略掉此字段,所以反序列化出的对象,被 transient 修饰的属性是默认值。对于引用类型,值是 null;基本类型,值是 0;boolean 类型,值是 false。

Externalizable

Externalizable 接口不同于 Serializable 接口,实现此接口必须实现接口中的两个方法实现自定义序列化,这是强制性的;特别之处是必须提供 public 的无参构造器,因为在反序列化的时候需要反射创建对象。

虽然 Externalizable 接口带来了一定的性能提升,但变成复杂度也提高了,所以一般通过实现 Serializable 接口进行序列化。

serialVersionUID

序列化版本号可自由指定,如果不指定,JVM 会根据类信息自己计算一个版本号,这样随着 class 的升级,就无法正确反序列化;不指定版本号另一个明显隐患是,不利于 jvm 间的移植,可能 class 文件没有更改,但不同 jvm 可能计算的规则不一样,这样也会导致无法反序列化。

什么情况下需要修改serialVersionUID呢?分三种情况。

如果只是修改了方法,反序列化不容影响,则无需修改版本号

如果只是修改了静态变量,瞬态变量(transient修饰的变量),反序列化不受影响,无需修改版本号

如果修改了非瞬态变量,则可能导致反序列化失败。如果新类中实例变量的类型与序列化时类的类型不一致,则会反序列化失败,这时候需要更改serialVersionUID。如果只是新增了实例变量,则反序列化回来新增的是默认值;如果减少了实例变量,反序列化时会忽略掉减少的实例变量

总结

所有需要网络传输的对象都需要实现序列化接口,通过建议所有的javaBean都实现Serializable接口。

对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化。

如果想让某个变量不被序列化,使用transient修饰。

序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。

反序列化时必须有序列化对象的class文件。

当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。

单例类序列化,需要重写readResolve()方法;否则会破坏单例原则。

同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化。

建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值