【源碼系列-1】Serializable

  • 序列化:
    序列化是指把對象轉換爲字節序列的過程,我們稱之爲對象的序列化,就是把內存中的這些對象變成一連串的字節(bytes)描述的過程。

  • 反序列化:
    就是把持久化的字節文件數據恢復爲對象的過程。那麼什麼情況下需要序列化呢?大概有這樣兩類比較常見的場景:1)、需要把內存中的對象狀態數據保存到一個文件或者數據庫中的時候,這個場景是比較常見的,例如我們利用mybatis框架編寫持久層insert對象數據到數據庫中時;2)、網絡通信時需要用套接字在網絡中傳送對象時,如我們使用RPC協議進行網絡通信時;

  • 序列化的應用場景:
    實現serializabel接口的作用是就是可以把對象存到字節流,並且可以恢復,是實現持久化和持久化和網絡傳輸的基礎,要持久化和網絡傳輸就得轉爲字節流,應用於分佈式應用中及涉及數據持久化的場景。

  • 實現java.io.Serializable接口的類可以進行序列化。

  • 這個接口沒有任何方法,只是語義上表面這個實現類可以進行序列化。

  • 一個沒有實現序列化的子類想要實現序列化的話,必須保存父類的public,protected作用域。這樣做的前提是父類有無參構造函數,否則會在運行時報錯。

  • 在反序列化的過程中,無法實現序列化的類將通過public或protected無參構造函數初始化,可序列化的子類將會被存儲在流中。

  • 當對圖片進行轉換的時候,對象可能會不支持序列化接口,會拋出NotSerializableException異常。

  • 序列化或反序列化的類需要實現以下方法:

    • private void writeObject(java.io.ObjectOutputStream out) throws IOException
    • private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
    • private void readObjectNoData() throws ObjectStreamException;
  • writeObject方法用來寫對象的狀態,以便readObject可以恢復對象狀態。默認的保存對象狀態的機制是調用out.defaultWriteObject。這個方法不關注狀態是屬於子類還是父類,保存狀態的兩種方法:

    1. 使用writeObject把作用域寫入ObjectOutputStream
    2. 使用DataOutput支持的方法
  • readObject方法通過讀取流恢復類作用域。默認的恢復對象的非靜態和非暫時域是通過調用in.defaultReadObject實現的。defaultReadObject方法給保存在流裏面的對象賦作用域。這個方法不關心狀態是屬於父類還是子類。

  • readObjectNoData方法在父類沒有被序列化的情況下,用來初始化該類對象的狀態。當序列化使反序列化的實例的類版本與方法接收到的不一致時,或者是序列化後的二進制流被竄改也會調用readObjectNoData方法。

  • serialVersionUID用於對序列化的類做版本標識,在反序列化的過程中驗證是否爲對象加載了與序列化兼容的類。如果receiver加載的類和sender加載的類的serialVersionUID不同,反序列化會報InvalidClassException。因此,在序列化之前,應該在類裏生命一個serialVersionUID成員變量。

  • private static final long serialVersionUID = 42L;

  • 如果沒有顯式聲明,則在運行時會分配一個默認的serialVersionUID,因爲serialVersionUID的計算可能會因編譯器的不同而不同,可能會報InvalidClassException,因此建議在序列化時顯式聲明serialVersionUID,且應該使用private修飾符,以免該屬性被子類繼承。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章