1. 程式人生 > >Java Serializable介面實現問題

Java Serializable介面實現問題

JavaBeans

      要了解Serializable介面之前先來了解最基本的JavaBeans。JavaBeans為我們提供了最簡單的Java類實體,這些實體伴隨著業務在應用中來回穿梭。JavaBeans是Java中一種特殊的類,可以將多個物件封裝到一個物件(bean)中。特點是可序列化,提供無參構造器,提供getter方法和setter方法訪問物件的屬性。名稱中的“Bean”是用於Java的可重用軟體元件的慣用叫法。

   JavaBeans優點:
   (1) Bean可以控制它的屬性、事件和方法是否暴露給其他程式。
   (2) Bean可以接收來自其他物件的事件,也可以產生事件給其他物件。
   (3) 有軟體可用來配置Bean。
   (4) Bean的屬性可以被序列化,以供日後重用。

   JavaBeans規範:

    要成為JavaBean類,則必須遵循關於命名、構造器、方法的特定規範。有了這些規範,才能有可以使用、複用、替代和連線JavaBeans的工具。規範如下:

    (1)有一個公有的無參構造器。
    (2) 屬性可以通過get、set、is(可以替代get,用在布林型屬性上)方法或遵循特定命名規範的其他方法訪問。
    (3)可序列化。

  JavaBean例子:

注:以上使用的是預設的serialVersionUID,會被警告,因為這樣不符合Java的效能要求。

Serializable

        Java類通過實現 java.io.Serializable 介面以啟用其序列化功能。未實現此介面的類將無法使其任何狀態序列化或反序列化。可序列化類的所有子型別本身都是可序列化的。序列化介面沒有方法或欄位,僅用於標識可序列化的語義。要允許不可序列化類的子型別序列化,可以假定該子型別負責儲存和還原超型別的公用 (public)、受保護的 (protected) 和(如果可訪問)包 (package) 欄位的狀態。僅在子型別擴充套件的類(父類)有一個可訪問的無引數構造方法來初始化該類的狀態時,才可以假定子型別有此責任。如果不是這種情況,則宣告一個類為可序列化類是錯誤的。該錯誤將在執行時檢測到。在反序列化過程中,將使用該類的公用或受保護的無引數構造方法初始化不可序列化類的欄位。可序列化的子類必須能夠訪問無引數的構造方法。可序列化子類的欄位將從該流中還原。

     serialVersionUID

      序列化執行時使用一個稱為 serialVersionUID 的版本號與每個可序列化類相關聯,該序列號在反序列化過程中用於驗證序列化物件的傳送者和接收者是否為該物件載入了與序列化相容的類。如果接收者載入的該物件的類的 serialVersionUID 與對應的傳送者的類的版本號不同,則反序列化將會導致 InvalidClassException。可序列化類可以通過宣告名為 "serialVersionUID" 的欄位(該欄位必須是靜態 (static)、最終 (final) 的 long 型欄位)顯式宣告其自己的 serialVersionUID:


       如果可序列化類未顯式宣告 serialVersionUID,則序列化執行時將基於該類的各個方面計算該類的預設 serialVersionUID 值,如“Java(TM) 物件序列化規範”中所述。不過,強烈建議 所有可序列化類都顯式宣告 serialVersionUID 值,原因計算預設的 serialVersionUID 對類的詳細資訊具有較高的敏感性,根據編譯器實現的不同可能千差萬別,這樣在反序列化過程中可能會導致意外的 InvalidClassException。因此,為保證 serialVersionUID 值跨不同 java 編譯器實現的一致性,序列化類必須宣告一個明確的 serialVersionUID 值。還強烈建議使用 private 修改器顯示宣告 serialVersionUID(如果可能),原因是這種宣告僅應用於立即宣告類 -- serialVersionUID 欄位作為繼承成員沒有用處。
        實現java.io.Serializable 介面的類是可序列化的。沒有實現此介面的類將不能使它們的任一狀態被序列化或逆序列化。
        序列化類的所有子類本身都是可序列化的。這個序列化介面沒有任何方法和域,僅用於標識序列化的語意。允許非序列化類的子型別序列化,子型別可以假定負責儲存和恢復父型別的公有的、保護的和(如果可訪問)包的域的狀態。只要該類(即父類)有一個無參構造子,可初始化它的狀態,那麼子型別就可承擔上述職責;如果該類沒有無參建構函式,在這種情況下申明一個可序列化的類是一個錯誤。此錯誤將在執行時被檢測。

      任何型別只要實現了Serializable介面,就可以被儲存到檔案中,或者作為資料流通過網路傳送到別的地方。也可以用管道來傳輸到系統的其他程式中。

提供案例

      如下所示的兩個方法,都沒有問題,實質的問題在他們傳遞的SortingQualityCollection物件(JavaBean):


        在程式執行時,save和update方法都可以執行成功,但是永遠返回的狀態都是false,這一點很讓人費解,在debug後發現使用Spring AOP的使用是不能夠成功的,另外最直接的錯誤是報出cglib的資源不存在。很疑惑的是,程式執行成功了update和insert的語句在後臺也打印出來了,資料庫中記錄正確,由於返回的是false導致程式中業務處理始終不能往下進行。

       對比過程:檢視資料物件和資料庫欄位是否一致、另外JavaBean是否規範。但做完這些事情還是無濟於事,後來問題只能鎖定在JavaBean上。JavaBean是通過工具生成的,serialVersionUID如下:

      於是重新生成serialVersionUID,新的serialVersionUID如下:

    重新執行程式,程式執行成功,由此可見serialVersionUID的宣告很重要,最好在寫完JavaBean之後手動生成之,並且顯示宣告。