問:什麼是 j**a 序列化?
乙個:J**A 提供了兩種持久化物件的方法,即序列化和外部序列化。
序列化
在分布式環境中,當遠端通訊時,無論哪種型別的資料以二進位順序通過網路傳輸。 序列化是將物件描述為一系列位元組的過程,以解決讀取和寫入物件流時出現的問題。序列化可以將物件的狀態寫入流進行網路傳輸,也可以將其儲存到檔案、資料庫或其他系統中,並在需要時讀出流以重建相同的物件。
你是怎麼做到的?事實上,所有要序列化的類都必須實現 Serializable 介面,該介面位於 J**A 中lang 包,它不包含任何方法。 使用輸出流(例如 FileOutputStream)構造 ObjectOutputStream 物件,然後使用該物件的 WriteObject(ObjectObJ) 方法寫出 ObjectOutput 物件(即儲存其狀態)並使用其對應的輸入流進行恢復。
序列化有兩個特點:
1)如果乙個類可以序列化,那麼它的子類也可以序列化。
2)由於static表示類的成員transient(j**a關鍵字),如果用transient宣告例項變數,則在儲存物件時不需要維護其值。) 表示物件的臨時資料,因此不能將其序列化為這兩種型別的資料的成員。
J**A 提供了多個物件序列化介面,包括 ObjectOutput、ObjectInput、ObjectOutputStream 和 ObjectInputStream。
由於使用序列化會影響系統的效能,因此在沒有必要時不應使用它。那麼,何時需要使用該序列化呢?
1)物件需要通過網路傳送,或者物件的狀態需要持久化到資料庫或檔案中。
2)序列化可以實現深度複製,即可以複製被引用的物件。
序列化的對立面是反序列化,它將流轉換為物件。 在序列化和反序列化的過程中,serialversionuid 起著非常重要的作用,每個類都有乙個特定的 serialversionuid,在反序列化的過程中,類的相容性由 serialversionuid 決定。 如果待序列化物件的serialversionuid與目標物件的serialversionuid不同,則在反序列化時會丟擲invalidclassexception。 作為乙個好的程式設計習,最好在序列化類中顯式宣告serialversionuid(此欄位必須定義為靜態final)。 自定義 serialversionuid 具有以下三個優點:
提高程式的執行效率。 如果未在類中顯式宣告 SerialVersionuid,則在序列化時計算 SerialVersionuid 值。 通過顯式宣告 serialversionuid,省略了計算過程,從而提高了程式的效率。
提高程式在不同平台上的相容性。由於每個平台的編譯器在計算 serialversionuid 時完全有可能使用不同的計算,因此不可能在另乙個平台上反序列化乙個平台上序列化的物件。 可以通過顯式宣告 SerialVersionUid 來避免此問題。
增強程式所有版本的相容性。預設情況下,每個類都有乙個唯一的 SerialVersionUid,因此當以後對類進行修改時(例如通過新增新屬性),該類的 serialVersionuid 的值將發生變化,這將導致該類在修改前序列化的檔案在修改後被反序列化。 同樣,這將通過顯式宣告 SerialVersionuid 來解決。
外部序列化。
J**a 語言還提供了另一種實現物件持久化的方法,即外部序列化。介面如下:
外部序列化和序列化之間的主要區別在於序列化是內建的API,只需要實現可序列化的介面,開發者不需要寫任何**來實現物件的序列化,而使用外部序列化時,可外部化介面中的讀寫方法必須由開發者實現。因此,使用 externalizable 編寫程式比實現可序列化介面更困難,但由於它將控制權交到開發人員手中,因此程式設計具有更大的靈活性,並且控制那些需要持久化的屬性的能力可能會提高效能。
擴充套件:序列化可序列化時,該類中的所有屬性都會被序列化,那麼如何只序列化部分屬性呢?
一種方法實現了可外部化的介面,開發者可以根據實際需要實現readexternal和writeexternal方法來控制用於序列化和反序列化的屬性,這樣做的缺點是增加了程式設計的難度。 執行此操作的另一種方法是使用關鍵字 transient 來控制序列化的屬性。 由瞬態修改的屬性是臨時的,不會序列化。 因此,可以修改不需要使用瞬態序列化的屬性。