默認的序列化方式不適合,采用自定義序列化的方式
例hashMap中對元素的存儲。java 7中hashMap元素的存儲結構為 表 (table)+ 鏈(結點構成的鏈)的存儲結構。其中根據hash(key)求的對應元素在table的索引,並將元素插入此索引處的鏈表。
其中的實例域table 即為transient
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
transient Entry[] table = (Entry[]) EMPTY_TABLE;
那麼問題來了,既然table中存儲著hashMap中的元素信息,為什麼不序列化?
答:不是不序列化,而是不采用默認的序列化。
由於table中元素信息是我們存取關注的,而非table的結構,所以能合理的完成table中所有信息的存取是關鍵。
鑒於table結構過於復雜(其中的鏈表結構為Entry 結點構成的鏈表),若采用默認的序列化方式,會將table的完整結構(包括各鏈表)鏡像一份,如此以來帶來一下弊端:
1. 不僅需要消化大量時間遍歷table結構
2. 占用較多的存儲空間
3. 默認序列化對對象圖做遞歸遍歷當表過大時會發生堆棧溢出,所以避免使用默認的序列化方式。
hashMap中采用序列化存儲過程中遍歷table中元素,並逐一序列化儲存。而在序列化讀取過程中,根據讀出數值還原表結構的方式來完成,從而提高序列化的質量。過程如下:
private void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
// Write out the threshold, loadfactor, and any hidden stuff
s.defaultWriteObject();
….
//自定義完成table中信息的存儲
// Write out keys and values (alternating)
if (size > 0) {
for(Map.Entry e : entrySet0()) {
s.writeObject(e.getKey());
s.writeObject(e.getValue());
}
}
}
private static final long serialVersionUID = 362498820763181265L;
/**
* Reconstitute the {@code HashMap} instance from a stream (i.e.,
* deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
{
// Read in the threshold (ignored), loadfactor, and any hidden stuff
s.defaultReadObject();
...
//依次讀取,並還原表結構
// Read the keys and values, and put the mappings in the HashMap
for (int i = 0; i < mappings; i++) {
K key = (K) s.readObject();
V value = (V) s.readObject();
putForCreate(key, value);
}
}
如此,當自定義中實例域存儲機構將復雜,默認序列化方式無法勝任時,可以聲明為transient,並自定義完成該字段中信息的序列化。