建議12:避免用序列化類(lèi)在構(gòu)造函數(shù)中為不變量賦值
一般來(lái)說(shuō),final標(biāo)識(shí)的屬性是不變量,也就是說(shuō)只能賦值一次,不能重復(fù)賦值,但是在序列化類(lèi)中有些不一樣。
public class Person implemnets Serializable{
private static final long serialVersionUID = 71282334L;
//不變量
public final String name = "混世魔王";
}
這個(gè)Person類(lèi)(此時(shí)V1.0版本)被序列化,然后存儲(chǔ)在磁盤(pán)上,在被反序列化時(shí)name屬性會(huì)重新計(jì)算其值,(這與static變量不同,static變量壓根就沒(méi)有保存在數(shù)據(jù)流中),比如name屬性修改成了“德天使”(版本升級(jí)為V2.0),那么反序列化對(duì)象的name值就是“德天使”。也就是說(shuō),如果final屬性是一個(gè)直接量,在反序列化時(shí)就會(huì)重新計(jì)算。
接下來(lái)看另一種賦值方法:通過(guò)構(gòu)造函數(shù)賦值。
public class Person implements Serializable {
private static final long serialVersionUID = 91282334L;
public final String name;
public Person(){
name = "混世魔王";
}
}
然后進(jìn)行序列化,然后在修改name="德天使",接著反序列化。結(jié)果name仍然是“混世魔王”。
** 這里涉及到反序列化的另一個(gè)規(guī)則:反序列化時(shí)構(gòu)造函數(shù)不會(huì)執(zhí)行**
反序列化的過(guò)程是這樣的:JVM從數(shù)據(jù)流中獲取一個(gè)Object對(duì)象,然后根據(jù)數(shù)據(jù)流中的類(lèi)文件描述信息(在序列化時(shí),保存到磁盤(pán)的對(duì)象文件中包含了類(lèi)的描述信息,注意是類(lèi)描述信息,不是類(lèi))查看,發(fā)現(xiàn)是final變量,需要重新計(jì)算,于是引用Person類(lèi)中的name值,而此時(shí)JVM又發(fā)現(xiàn)name竟然沒(méi)有復(fù)制,不能引用,于是它不在初始化,保持原值狀態(tài),所以仍然是“混世魔王”。