1.10 对象序列化控制输入输出
對象序列化是什么
對象序列化(Serialize)指將一個 Java 對象寫入 IO 流中,與此對應的是,對象的反序列化(Deserialize)則指從 IO 流中恢復該 Java 對象。如果想讓某個 Java 對象能夠序列化,則必須讓它的類實現 java.io.Serializable 接口,接口定義如下:
public interface Serializable { }Serializable 接口是一個空接口,實現該接口無須實現任何方法,它只是告訴 JVM 該類可以被序列化機制處理。通常建議程序創建的每個 JavaBean 類都實現 Serializable。
ObjectInput 接口與 ObjectOutput 接口分別繼承了 DataInput 和 DataOutput 接口,主要提供用于讀寫基本數據和對象數據的方法。
ObjectInput 接口提供了 readObject() 方法,此方法用于將對象從流中讀出
ObjectOutput 提供了 writeObject() 方法,此方法用于將對象寫入流中。
因為 ObjectInput 與 ObjectOutput 都是接口,所以不能創建對象,只能使用分別實現了這兩個接口的 ObjectInputStream 類和 ObjectOutputStream 類來創建對象。
下面講解如何使用 ObjectInputStream 類和 ObjectOutputStream 類來操作數據。
序列化
ObjectOutputStream 類繼承了 OutputStream 類,同時實現了 ObjectOutput 接口,提供將對象序列化并寫入流中的功能,該類的構造方法如下:
public ObjectOutputStream (OutputStream out)該構造方法需要傳入一個 OutputStream 對象,用來表示將對象二進制流寫入到指定的 OutputStream 中。
程序通過以下兩個步驟來序列化對象:
1)創建一個 ObjectOutputStream 對象,如下代碼所示。
// 創建個 ObjectOutputStream 輸出流 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));2)調用 ObjectOutputStream 對象的 writeObject() 方法輸出可序列化對象,如下代碼所示。
// 將一個 Person 對象輸出到輸出流中
例 1
下面程序定義了一個 Person 類,這個 Person 類就是一個普通的 Java 類,只是實現了 Serializable 接口,該接口表示該類的對象是可序列化的。
注意:Person 類的兩個成員變量分別是 String 類型和 int 類型的。如果某個類的成員變量的類型不是基本類型或 String 類型,而是另一個引用類型,那么這個引用類型必須是可序列化的,否則擁有該類型成員變量的類也是不可序列化的。
下面程序使用 ObjectOutputStream 將一個 Person 對象寫入到磁盤文件。
public class WriteObject {public static void main(String[] args) throws Exception {// 創建一個 ObjectOutputStream 輸出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));Person per = new Person("你好你好你好", 7);// 將 Per對象寫入輸出流oos.writeObject(per);} }上面程序中的第 4 行代碼創建了一個 ObjectOutputStream 輸出流,這個 ObjectOutputStream 輸出流建立在一個文件輸出流的基礎之上。程序第 7 行代碼使用 writeObject() 方法將一個 Person 對象寫入輸出流。運行上面程序,將會看到生成了一個 object.txt 文件,該文件的內容就是 Person 對象。
反序列化
ObjectInputStream 類繼承了 InputStream 類,同時實現了 ObjectInput 接口,提供了將對象序列化并從流中讀取出來的功能。該類的構造方法如下:
public ObjectInputStream(InputStream out)該構造方法需要傳入一個 InputStream 對象,用來創建從指定 InputStream 讀取的 ObjectInputStream。
反序列化的步驟如下所示:
1)創建一個 ObjectInputStream 輸入流,這個輸入流是一個處理流,所以必須建立在其他節點流的基礎之上。如下代碼所示。
// 創建一個ObjectInputStream輸入流 ObjectInputStream ois = new ObjectInputStream (new FileInputStream ("object. txt"));2)調用 ObjectInputStream 對象的 readObject() 方法讀取流中的對象,該方法返回一個 Object 類型的 Java 對象,如果程序知道該 Java 對象的類型,則可以將該對象強制類型轉換成其真實的類型。如下代碼所示。
// 從輸入流中讀取一個Java對象,并將其強制類型轉換為Person類 Person P = (Person)ois.readObject();例 2
下面程序是從例 1 中生成的 object.txt 文件來讀取 Person 對象的步驟。
上面程序中第 4 行粗體字代碼將一個文件輸入流包裝成 ObjectInputStream 輸入流,第 6 行代碼使用 readObject() 讀取了文件中的 Java 對象,這就完成了反序列化過程。
反序列化讀取的僅僅是 Java 對象的數據,而不是 Java 類,因此采用反序列化恢復 Java 對象時,必須提供該 Java 對象所屬類的 class 文件,否則將會引發 ClassNotFoundException 異常。
Person 類只有一個有參數的構造器,沒有無參數的構造器,而且該構造器內有一個普通的打印語句。當反序列化讀取 Java 對象時,并沒有看到程序調用該構造器,這表明反序列化機制無須通過構造器來初始化 Java 對象。
如果使用序列化機制向文件中寫入了多個 Java 對象,使用反序列化機制恢復對象時必須按實際寫入的順序讀取。當一個可序列化類有多個父類時(包括直接父類和間接父類),這些父類要么有無參數的構造方法,要么也是可序列化的,否則反序列化時將拋出 InvalidClassException 異常。如果父類是不可序列化的,只是帶有無參數的構造方法,則該父類中定義的成員變量值不會序列化到 IO 流中。
Java序列化編號
Java 序列化機制是通過類的序列化編號(serialVersionUID)來驗證版本一致性的。在反序列化時,JVM 會把傳來字節流中的序列化編號和本地相應實體類的序列化編號進行比較,如果相同就認為一致,可以進行反序列化,否則會拋出 InvalidCastException 異常
序列化編號有兩種顯式生成方式:
- 默認的1L,比如:private static final long serialVersionUID = 1L。
- 根據類名、接口名、成員方法及屬性等來生成一個 64 位的哈希字段。
當實現 Serializable 接口的對象沒有顯式定義一個序列化編號時,Java 序列化會根據編譯的 Class 自動生成一個序列化編號,這種情況下只要 class 文件發生變化,序列化號就會改變,否則一直不變。
總結
以上是生活随笔為你收集整理的1.10 对象序列化控制输入输出的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1.9 Java转换流:InputStr
- 下一篇: 1.11实例:保存图书信息