建議12:避免用序列化類在構(gòu)造函數(shù)中為不變量賦值
一般來說童谒,final標(biāo)識(shí)的屬性是不變量象浑,也就是說只能賦值一次愉豺,不能重復(fù)賦值蚪拦,但是在序列化類中有些不一樣盛嘿。
public class Person implemnets Serializable{
private static final long serialVersionUID = 71282334L;
//不變量
public final String name = "混世魔王";
}
這個(gè)Person類(此時(shí)V1.0版本)被序列化,然后存儲(chǔ)在磁盤上类垦,在被反序列化時(shí)name屬性會(huì)重新計(jì)算其值米苹,(這與static變量不同良瞧,static變量壓根就沒有保存在數(shù)據(jù)流中)褥蚯,比如name屬性修改成了“德天使”(版本升級為V2.0),那么反序列化對象的name值就是“德天使”歧强。也就是說摊册,如果final屬性是一個(gè)直接量,在反序列化時(shí)就會(huì)重新計(jì)算白修。
接下來看另一種賦值方法:通過構(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í)行**
反序列化的過程是這樣的:JVM從數(shù)據(jù)流中獲取一個(gè)Object對象,然后根據(jù)數(shù)據(jù)流中的類文件描述信息(在序列化時(shí)泰讽,保存到磁盤的對象文件中包含了類的描述信息,注意是類描述信息累澡,不是類)查看,發(fā)現(xiàn)是final變量翅雏,需要重新計(jì)算,于是引用Person類中的name值橄抹,而此時(shí)JVM又發(fā)現(xiàn)name竟然沒有復(fù)制,不能引用疟羹,于是它不在初始化参淫,保持原值狀態(tài),所以仍然是“混世魔王”耍铜。