建議13:避免為final變量復(fù)雜賦值
為final變量賦值可以通過方法賦值泊柬,即直接在聲明時(shí)通過方法返回值賦值。
public class Person implements Serializable {
private static final long serialVerisionUID = 91282334L;
//通過方法返回值為final變量賦值
public final String name = initName();
//初始化方法名
public String initName(){
return "混世魔王";
// return "德天使";
}
}
先序列化上面的代碼诈火,然后把initName的返回值改為注釋的代碼兽赁。然后在反序列化,name值是什么?
是“混世魔王”刀崖,雖然上一條建議說final變量會(huì)被重新賦值惊科,其中的“值”指的是簡(jiǎn)單對(duì)象,簡(jiǎn)單對(duì)象包括:8個(gè)基本數(shù)據(jù)類型亮钦,以及數(shù)組馆截,字符串(字符串情況很復(fù)雜,不通過new關(guān)鍵字生成String對(duì)象的情況下蜂莉,final變量的賦值與基本類型相同)蜡娶,但是不能通過方法賦值。
其中的原理是這樣的映穗,保存到磁盤上(或網(wǎng)絡(luò)傳輸)的對(duì)象文件包括兩部分:
(1)類描述信息
包括包路徑窖张、繼承關(guān)系、訪問權(quán)限蚁滋、變量描述宿接、變量訪問權(quán)限、方法簽名辕录、返回值睦霎,以及變量的關(guān)聯(lián)類信息。要注意的一點(diǎn)是踏拜,它并不是class文件的翻版碎赢,它不記錄方法、構(gòu)造函數(shù)速梗、static變量等的具體實(shí)現(xiàn)。之所以類描述會(huì)被保存襟齿,很簡(jiǎn)單姻锁,是因?yàn)槟苋ヒ材芑芈铮@保證反序列化的健壯運(yùn)行猜欺。
(2)非瞬態(tài)(transient關(guān)鍵字)和非靜態(tài)(static關(guān)鍵字)的實(shí)例變量值
注意位隶,這里的值如果是一個(gè)基本類型,就是一個(gè)簡(jiǎn)單值保存下來开皿;如果是復(fù)雜對(duì)象涧黄,連該對(duì)象和關(guān)聯(lián)類信息一起保存,并且持續(xù)遞歸下去(關(guān)聯(lián)類也必須實(shí)現(xiàn)Serializable接口赋荆,否則會(huì)出現(xiàn)序列化異常)笋妥,也就是說遞歸到最后,其實(shí)還是基本數(shù)據(jù)類型的保存窄潭。
正是因?yàn)檫@兩點(diǎn)原因春宣,一個(gè)持久化后的對(duì)象文件會(huì)比一個(gè)class類文件大很多。
總結(jié)一下,反序列化時(shí)final變量在以下情況下不會(huì)被重新賦值:
- 通過構(gòu)造函數(shù)為final變量賦值月帝。
- 通過方法返回值為final變量賦值躏惋。
- final修飾的屬性不是基本類型。