如果一个变量同时包含 transient 和 static 关键字,并且该值在声明期间被初始化,则它将被序列化。因为在这里 transient 修饰符会被忽略,而 static 修饰符将执行操作。
final 变量将被序列化。
如果一个变量同时包含 final 和 transient 关键字,那么它就会被序列化。因为在这里 transient 修饰符会被忽略,而 final 修饰符将执行操作。
下面用一段代码验证一些。
1、定义一个实例化类
2、序列化
3、反序列化
4、输出结果
重点:
One 和 Two 为 null,根据规则 1,使用 tresient 修饰的变量不参与序列化
Three 为 null,根据规则 2, static 变量不参与序列化
Four 之所以为 V4,根据规则 3,仅在声明期间初始化该值,静态变量才会被序列化
Five 为 null,根据规则4,因为它被 static 和 tresient 同时修饰,并且值在生命期间未初始化
Six 之所以为 6,根据规则 4,如果同时 static 和 tresient 同时修饰,并且该值在声明期间已初始化,那就会被序列化
Seven 是 V7,根据规则 5,用 final 修饰的会被序列化
Eight 之所以为 V8,根据规则 6,如果变量同时被 final 和 tresient 修饰,那就会被序列化
serialVersionUID 具体作用是什么?
在序列化中,还有一个特别重要的步骤,需要指定 serialVersionUID 版本号。
如果反序列化使用的 Class 的版本号与序列化时候使用的不一致,则会报异常。
序列化版本号可以随意的指定。
如果不指定,JVM 会 自己计算 一个版本号,但随着 Class 的升级,就无法正确反序列化。
不指定版本号还有另一个明显隐患,不利于 JVM 间的移植,可能 Class 文件没有更改,但不同 JVM 可能计算的规则不一样,这样也会导致无法反序列化。
Java 序列化的缺陷无法跨平台
现在的系统设计越来越多元化,项目里可能会用多种语言来编写应用程序,比如 Java、C++、Python 同时配合使用。
而 Java 序列化只适用于基于 Java 语言实现的框架。其他语言大部分没有使用 Java 的序列化框架。如果两个基于不同语言编写的应用程序相互通信,那么久无法实现两个应用服务之间的序列化与反序列化。
容易被攻击