建议12:避免用序列化类在构造函数中为不变量赋值
一般来说,final标识的属性是不变量,也就是说只能赋值一次,不能重复赋值,但是在序列化类中有些不一样。
public class Person implemnets Serializable{
private static final long serialVersionUID = 71282334L;
//不变量
public final String name = "混世魔王";
}
这个Person类(此时V1.0版本)被序列化,然后存储在磁盘上,在被反序列化时name属性会重新计算其值,(这与static变量不同,static变量压根就没有保存在数据流中),比如name属性修改成了“德天使”(版本升级为V2.0),那么反序列化对象的name值就是“德天使”。也就是说,如果final属性是一个直接量,在反序列化时就会重新计算。
接下来看另一种赋值方法:通过构造函数赋值。
public class Person implements Serializable {
private static final long serialVersionUID = 91282334L;
public final String name;
public Person(){
name = "混世魔王";
}
}
然后进行序列化,然后在修改name="德天使",接着反序列化。结果name仍然是“混世魔王”。
** 这里涉及到反序列化的另一个规则:反序列化时构造函数不会执行**
反序列化的过程是这样的:JVM从数据流中获取一个Object对象,然后根据数据流中的类文件描述信息(在序列化时,保存到磁盘的对象文件中包含了类的描述信息,注意是类描述信息,不是类)查看,发现是final变量,需要重新计算,于是引用Person类中的name值,而此时JVM又发现name竟然没有复制,不能引用,于是它不在初始化,保持原值状态,所以仍然是“混世魔王”。