天天看點

JAVA 序列化 和 反序列化 (Externalizable Serializable) 那些事

序列化控制

  • 當我們對序列化進行控制時,可能某個特定子對象不想讓Java序列化機制自動儲存與恢複。如果子對象表示的是我們不希望将其序列化的敏感資訊(如密碼),通常會面臨這種情況。即使對象中的這些資訊是private屬性,一經序列化處理,人們就可以通過讀取檔案或者攔截網絡傳輸的方式來通路到它。有兩種辦法可以防止對象的敏感部分被序列化:
    • 實作

      Externalizable

      代替實作

      Serializable

      接口來對序列化過程進行控制,

      Externalizable

      繼承了

      Serializable

      接口,同時增添了兩個方法:

      writeExternal()

      readExternal()

    兩者在反序列化時的差別:

    - 對Serializable對象反序列化時,由于Serializable對象完全以它存儲的二進制位為基礎來構造,是以并不會調用任何構造函數,是以Serializable類無需預設構造函數,但是當Serializable類的父類沒有實作Serializable接口時,反序列化過程會調用父類的預設構造函數,是以該父類必需有預設構造函數,否則會抛異常。

    - 對Externalizable對象反序列化時,會先調用類的不帶參數的構造方法,這是有别于預設反序列方式的。如果把類的不帶參數的構造方法删除,或者把該構造方法的通路權限設定為private、預設或protected級别,會抛出

    java.io.InvalidException: no valid constructor

    異常,是以Externalizable對象必須有預設構造函數,而且必需是public的。

    Externalizable

    的替代方法:如果不是特别堅持實作Externalizable接口,那麼還有另一種方法。我們可以實作

    Serializable

    接口,并添加

    writeObject()

    readObject()

    的方法。一旦對象被序列化或者重新裝配,就會分别調用那兩個方法。也就是說,隻要提供了這兩個方法,就會優先使用它們,而不考慮預設的序列化機制。

    這些方法必須含有下列準确的簽名:

    private void writeObject(ObjectOutputStream stream) 
            throws IOException;
    private void readObject(ObjectInputStream stream)
            throws IOException, ClassNotFoundException
          
    - 可以用

    transient

    關鍵字逐個字段地關閉序列化,它的意思是“不用麻煩你儲存或恢複資料—我自己會處理的”。由于Externalizable對象在預設情況下不儲存它們的任何字段,是以transient關鍵字隻能和Serializable對象一起使用。