Effective Java之考虑自定义的序列化模式(七十五)
為什么自定義序列化?
這里直接舉一個書上的例子
public final class StringList implements Serializable {private int size = 0;private Entry head = null;private static class Entry implements Serializable {String data;Entry next;Entry previous;}.... }我們知道,序列一個類,會同時序列化它的組件。
也就是說,如果我序列化了“B”對象, B是雙向鏈表,它要序列化它的內部成員“A”和“C”對象,但是序列化“A”和“C”對象的時候,B同時也是它們的組件,也要序列化“B”~~~~~~~~
于是就進入了無窮的死循環中!!!
這時候,我們的需求很簡單,對于每個對象的Entry,我只序列化一次就行了,不需要迭代序列化。
于是就有了transient關鍵字
標記為transient的不會自動序列化,這就防止默認序列化做出錯誤的事情,然后調用writeObject手動序列化transient字段,做自己認為正確的事。readObject同理。
注意??:盡管StringList的所有域都是transient,但writeObject和readObject的首要任務仍是調用defaultXxxObject方法來序列化不帶有transient的字段,這樣可以極大的增強靈活性。因為萬一以后加入了不帶有transient的字段呢?
總結,自定義序列化目的就是做自己認為正確的事情,經典的例子有ArrayList和HashMap。
自定義序列化的例子
ArrayList
來看一下關鍵的實例域:
private static final Object[] EMPTY_ELEMENTDATA = {};/*** Shared empty array instance used for default sized empty instances. We* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when* first element is added.*/private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** The array buffer into which the elements of the ArrayList are stored.* The capacity of the ArrayList is the length of this array buffer. Any* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA* will be expanded to DEFAULT_CAPACITY when the first element is added.*/transient Object[] elementData; // non-private to simplify nested class access/*** The size of the ArrayList (the number of elements it contains).** @serial*/private int size;這里定義空數組是為什么呢?
答案就在這里:Effective Java之返回零長度的數組或者集合,而不是null(四十三)
然后為什么transient Object[] elementData;
難道不應該初始化它的所有數組元素嗎?
原因就是ArrayList實際上是動態數組,每次在放滿以后自動增長設定的長度值,如果數組自動增長長度設為100,而實際elementData里面有可能有1個實際對象,其他都是null,默認的初始化會初始化99個null對象,這顯然不合適!
所以,我們來欣賞一下它的writeObject方法:
HashMap
transient Node<K,V>[] table;原因1
因為讀寫Map是根據Object.hashcode()來確定從table[i]讀/寫,而Object.hashcode()是native方法, 不同的JVM里可能是不一樣的。比如向HashMap存一個鍵值對entry, key為字符串"hello", 在第一個java程序里, "hello"的hashcode()為1, 存入table【1】在另一個JVM程序里, "hello" 的hashcode()有可能就是2, 存入table【2】所以不管物理結構,序列化只負責把key,value送貨上門,具體放在哪個table,序列化不需要理會。原因2:
table 和 ArrayList的elementData 中存儲的值數量是小于數組的大小的(數組擴容的原因),這個在元素越來越多的情況下更為明顯。如果使用默認的序列化,那些沒有元素的位置也會被存儲,就會產生很多不必要的浪費。 超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的Effective Java之考虑自定义的序列化模式(七十五)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Effective Java之谨慎地实现
- 下一篇: Effective Java之保护性编写