被 transient 所修飾 table 變量
如果大家細心閱讀 HashMap 的源碼,會發現桶數組 table 被申明為 transient。transient 表示易變的意思,在 Java 中,被該關鍵字修飾的變量不會被默認的序列化機制序列化。我們再回到源碼中,考慮一個問題:桶數組 table 是 HashMap 底層重要的數據結構,不序列化的話,別人還怎么還原呢?
這里簡單說明一下吧,HashMap 並沒有使用默認的序列化機制,而是通過實現readObject/writeObject
兩個方法自定義了序列化的內容。這樣做是有原因的,試問一句,HashMap 中存儲的內容是什么?不用說,大家也知道是鍵值對
。所以只要我們把鍵值對序列化了,我們就可以根據鍵值對數據重建 HashMap。有的朋友可能會想,序列化 table 不是可以一步到位,后面直接還原不就行了嗎?這樣一想,倒也是合理。但序列化 talbe 存在着兩個問題:
- table 多數情況下是無法被存滿的,序列化未使用的部分,浪費空間
- 同一個鍵值對在不同 JVM 下,所處的桶位置可能是不同的,在不同的 JVM 下反序列化 table 可能會發生錯誤。
以上兩個問題中,第一個問題比較好理解,第二個問題解釋一下。HashMap 的get/put/remove
等方法第一步就是根據 hash 找到鍵所在的桶位置,但如果鍵沒有覆寫 hashCode 方法,計算 hash 時最終調用 Object 中的 hashCode 方法。但 Object 中的 hashCode 方法是 native 型的,不同的 JVM 下,可能會有不同的實現,產生的 hash 可能也是不一樣的。也就是說同一個鍵在不同平台下可能會產生不同的 hash,此時再對在同一個 table 繼續操作,就會出現問題。
綜上所述,大家應該能明白 HashMap 不序列化 table 的原因了。