Java Serializable的序列化與反序列化

Jun
appxtech
Published in
5 min readSep 25, 2020

簡單來說Serializable就是讓「物件」序列化後可以被傳輸或儲存。

在講Serializable之前,來先科普一下。數據的最小單位是位元,而1個位元組(1Byte)即8個bit(位元),也就是像01010011。在ASCII編碼裡「A」這個字為65→01000001(二進位)。而我們在電腦與朋友打字聊天時,其實傳輸的文字都是01000001這種位元(序列化),但電腦自動幫我們轉換為對應的文字(反序列化)。對於位元、位元組、二進位等有興趣的人,可以看一下資料處理相關的教科書,像是「計算機概論」等。

以下分為幾個部份來講解
— — — — — 1.序列化與反序列化的用作
— — — — — 2.序列化的方式
— — — — —3.反序列化的問題
— — — — — 4.serialVersionUID序列化ID

1.序列化與反序列化的用作

透過上面的說明,我們知道在電腦與網路的世界中,所有的資訊都是由01010011等(位元)所組成,因此無論透過任何介質在傳輸資料時,都要先將資料轉換為(位元)。對於Java來說最小的單位就是類別class。因此Serializable就是將類別序列化,變成可傳輸的(位元)方式,再透過反序列化組合而成原本的形態。就像是我們對於電腦檔案的複製或搬移,如下圖:

小分享
1986年的電影「變蠅人」(The Fly),講述的是世界萬物都是由分子組成的,因此透過「電子傳送艙」將任何物體(包含人),先分解成分子後再傳輸到另一端組合回為原來物體型態的故事。這是不是與Serializable序列化與反序列化很像。

2.序列化的方式

Java中最小的單位是類別class,因此要將類別變成可序列化的方式,就是在類別class中,去implements Serializable既可。那麼,接下來是否要做任何的變動呢?

不、需、要

打開Serializable這個Interface去看,你會發現裡面完全空無一物。

Serializable就像是個Tag(標籤),只是告訴Java這個類別class是可以被序列化。即然類別class可被Serializable序列化,相反的就能夠被反序列化(還原)。進而的,也可以設為不可被序列化,以及部份序列化transient與自定序列化Externalizable等。

3.反序列化的問題

反序列化中,就是要將所讀回來的Object轉成原本的物件型態,除了類別class內容需要完全一致外,其類別class的名稱以及類別class所在的Package名稱也需要完全相同,若是不相同則會出現ClassNotFoundException的錯誤

此外,對於序列化ID也需要相同一致也才能進行反序列化。而當需確保序列化與反序列化的類別class內容為相同外,可以另外加上序列化ID,也就是serialVersionUID。

4.serialVersionUID序列化ID

其實在序列化時,Java本身就會自動的幫類別class加上一組序列化的ID,這組序列化ID為19位(最多)的Long型態數字,預設的序列化ID有分二種,我暫先稱為隱藏式與可見式。

隱藏式的序列化ID,在類別class設為Serializable序列化時,Java會依照類別class的內容自動產出一組序號做為序列化ID,除非程式報錯(例如序列化ID不同,否則將不會在程式碼中看到這組ID)。而有趣的是,經過實驗後,當二個類別class的內容、名稱、Package路徑都相同,但明明就是不同的類別class,其隱藏的序列化ID,預設也會一模一樣。

可見式的序列化ID,則是在class類別中加入private static final long serialVersionUID = 19位(最多)的Long型態數字; serialVersionUID若是選擇預設,則會預設為1L。

此外也可以選擇帶入Java自動生成的序列化ID。

經過測試後,序列化或反序列化的任一方不設序列化ID(這時Serializable會自動產生一組隱藏的序列化ID),而另一方帶入自動生成的序列化ID時(前提前類別class內容及類別class路徑皆相同的情況下),Java會認為這二個類別class是相同的,因此可完成反序列化。

--

--