1. 程式人生 > >java.io.Serializable(序列化)介面詳細總結

java.io.Serializable(序列化)介面詳細總結

一、前言

  在參加工作後,做的第一個專案是電商專案。當時不會做專案,只能照貓畫虎。其中一個VO類為何要實現Serializable介面一直沒有理解,不實現這個Serializable,會報錯。如下是隨手寫的一個VO類Person.java:

import java.io.Serializable;
public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    //兩個屬性及getter、setter方法
    private String name;
    private
String age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } }

二、什麼是序列化、反序列化

  翻閱JDK1.8的官方開發文件,發現Serializable介面沒有方法和欄位,僅用於標識可序列化的VO類。不實現此介面的類的任何欄位(屬性)都不能序列化和反序列化。那麼什麼是序列化和反序列化呢?

由於序列化和反序列化概念太抽象,還是通過兩個場景來理解為上策。

  (場景一)以上面提到的Person.java為例。這個VO類中的兩個欄位name和age在程式執行後都在堆記憶體中,程式執行完畢後記憶體得到釋放,name和age的值也不復存在。如果現在計算機要把這個類的例項傳送到另一臺機器、或是想儲存這個VO類的例項到資料庫(持久化物件),以便以後再取出來用。這時就需要對這個類進行序列化,便於傳送或儲存。用的時候再反序列化重新生成這個物件的例項。

  (場景二)以搬桌子為例,桌子太大了不能通過比較小的門,我們要把它拆了再運進去,這個拆桌子的過程就是序列化。同理,反序列化就是等我們需要用桌子的時候再把它組合起來,這個過程就是反序列化。

  學到這裡就可以給“序列化”下一個定義了
  把原本在記憶體中的物件狀態 變成可儲存或傳輸的過程稱之為序列化。序列化之後,就可以把序列化後的內容寫入磁碟,或者通過網路傳輸到別的機器上。

  序列化前的物件和反序列化後得到的物件,內容是一樣的(且物件中包含的引用也相同),但兩個物件的地址不同。換句話說,序列化操作可以實現對任何可Serializable物件的”深度複製(deep copy)”。

三、什麼情況下需要序列化

通過上面的分析,我們不難看出,一下三種情況需要使用序列化介面:

a)當你想把的記憶體中的物件狀態儲存到一個檔案中或者資料庫中,以便可以在以後重新建立精確的副本;
b)當你想用套接字在網路上傳送物件的時候(從一個應用程式域傳送到另一個應用程式域中);
c)當你想通過RMI傳輸物件的時候;

四、注意事項:

a)序列化時,只對物件的狀態進行儲存,而不管物件的方法;
b)當一個父類實現序列化,子類自動實現序列化,不需要顯式實現Serializable介面;
c)當一個物件的例項變數引用其他物件,序列化該物件時也把引用物件進行序列化;
d)並非所有的物件都可以序列化。
e) 序列化會忽略靜態變數,即序列化不儲存靜態變數的狀態。靜態成員屬於類級別的,不能序列化。添加了static、transient關鍵字後的變數不能序列化。

五、序列化ID

private static final long serialVersionUID = 1L;

序列化 ID在 Eclipse 下提供了兩種生成策略,一個設為固定的 1L,另一個是隨機生成一個不重複的 long 型別資料(實際上是使用 JDK 工具生成)。一般如果沒有特殊需求,用預設的 1L 就可以,這樣可以確保反序列化成功。因為不同的序列化id之間不能進行序列化和反序列化。