1. 程式人生 > >為什麼java要實現介面Serializable

為什麼java要實現介面Serializable

Java的"物件序列化"能讓你將一個實現了Serializable介面的物件轉換成一組byte,這樣日後要用這個物件時候,你就能把這些byte資料恢復出來,並據此重新構建那個物件了。這一點甚至在跨網路的環境下也是如此,這就意味著序列化機制能自動補償作業系統方面的差異。也就是說,你可以在Windows機器上創鍵一個物件,序列化之後,再通過網路傳到Unix機器上,然後在那裡進行重建。你不用擔心在不同的平臺上資料是怎樣表示的,byte順序怎樣,或者別的什麼細節。

物件序列化本身就非常有趣,因為它能讓你實現"輕量級的persistence(lightweight persistence)"。所謂persistence是指,物件的生命週期不是由程式是否執行決定的;在程式的兩次呼叫之間物件仍然還活著。通過"將做過序列化處理的物件寫入磁碟,等到程式再次執行的時候再把它讀出來",你可以達到persistence的效果。之所以說"輕量級",是因為你不能用像"persistent"這樣的關鍵詞來直接定義一個物件,然後讓系統去處理所有細節(雖然將來有可能會這樣)。相反,你必須明確地進行序列化(serialize)和解序列化(deserialize)。如果你需要更為正式的persistence功能,可以考慮Java Data Object( 簡稱是JDO)或Hibernate之類的工具(

http://hibernate.sourceforge.net)。

之所以要在語言里加入物件序列化是因為要用它來實現兩個重要的功能。Java的遠端方法呼叫(Remote Method Invocation簡稱RMI)能讓你像呼叫自己機器上的物件那樣去呼叫其它機器上的物件。當你向遠端物件傳遞訊息的時候,就需通過物件序列化來傳送引數和返回值了。RMI會在Thinking in Enterprise Java作討論。

我們會在第14章講到JavaBean。對JavaBean來說,物件序列化也是必不可少的。Bean的狀態資訊通常是在設計時配置的。這些狀態資訊必須儲存起來,供程式啟動的時候用;物件序列化就負責這個工作。

序列化一個物件還是比較簡單的,只要讓它實現Serializable介面就行了(這是一個"標記介面(tagging interface)",沒有任何方法)。但是,當語言引入序列化概念之後,它的很多標準類庫的類,包括primitive的wrapper類,所有的容器類,以及別的很多類,都會相應地發生改變。甚至連Class物件都會被序列化。

要想序列化物件,你必須先建立一個OutputStream,然後把它嵌進ObjectOutputStream。這時,你就能用writeObject( )方法把物件寫入OutputStream了。讀的時候,你得把InputStream嵌到ObjectInputStream裡面,然後再呼叫readObject( )方法。不過這樣讀出來的,只是一個Object的reference,因此在用之前,還得先下傳。

物件序列化最聰明的一點是,它不僅能儲存物件的副本,而且還會跟著物件裡面的reference,把它所引用的物件也儲存起來,然後再繼續跟蹤那些物件的reference,以此類推。這種情形常被稱為"單個物件所聯結的'物件網'"。這個機制所涵蓋的範圍不僅包括物件的成員資料,而且還包含數組裡面的reference。如果你要自己實現物件序列化的話,那麼編寫跟蹤這些連結的程式將會是一件非常痛苦的任務。但是,Java的物件序列化就能精確無誤地做到這一點,毫無疑問,它的遍歷演算法是做過優化的。

---------------------------------------------------------------------

實現java.io.Serializable 介面的類是可序列化的。沒有實現此介面的類將不能使它們的任一狀態被序列化或逆序列化。

  序列化類的所有子類本身都是可序列化的。這個序列化介面沒有任何方法和域,僅用於標識序列化的語意。允許非序列化類的子型別序列化,子型別可以假定負責儲存和恢復父型別的公有的、保護的和(如果可訪問)包的域的狀態。只要該類(擴充套件)有一個無參構造子,可初始化它的狀態,那麼子型別就可承擔上述職責。在這種情況下申明一個可序列化的類是一個錯誤。此錯誤將在執行時被檢測。就是可以把物件存到位元組流,然後可以恢復!

  例如:Integer實現了Serializable,所以可以把一個Integer的物件用IO寫到檔案裡,之後再可以從檔案裡讀出,如你開始寫入的時候那個物件的intValue() 是5的話,那讀出來之後也是5。這一點體現了用序化類的作用,即用來傳送類的物件。

  當一個JavaBean在構造工具內被使用者化,並與其它Bean建立連線之後,它的所有狀態都應當可被儲存,下一次被load進構造工具內或在執行時,就應當是上一次修改完的資訊。為了能做到這一點,要把Bean的某些欄位的資訊儲存下來,在定義Bean時要使它實現Java.io.Serializable介面。例如:

  public class Button implements Java.io.Serializable {……}

  實現了序列化介面的Bean中欄位的資訊將被自動儲存。若不想儲存某些字(這裡的Bean中欄位的資訊將被自動儲存是什麼意思?這個自動儲存是怎麼實現的?)

  段的資訊則可在這些欄位前冠以transient或static關鍵字,transient和static變數的資訊是不可被儲存的。通常,一個Bean所有公開出來的屬性都應當是被儲存的,也可有選擇地儲存內部狀態。Bean開發者在修改軟體時,可以新增欄位,移走對其它類的引用,改變一個欄位的private、protected或public狀態,這些都不影響類的儲存結構關係。然而,當從類中刪除一個欄位,改變一個變數在類體系中的位置,把某個欄位改成transient/static,或原來是transient/static,現改為別的特性時,都將引起儲存關係的變化。

  所謂的Serializable,就是java提供的通用資料儲存和讀取的介面。至於從什麼地方讀出來和儲存到哪裡去都被隱藏在函式引數的背後了。這樣子,任何型別只要實現了Serializable介面,就可以被儲存到檔案中,或者作為資料流通過網路傳送到別的地方。也可以用管道來傳輸到系統的其他程式中。這樣子極大的簡化了類的設計。只要設計一個儲存一個讀取功能就能解決上面說得所有問題。