當類別實作 java.io.Serializable
後,物件就可以被輸出到檔案中,稱為序列化。同樣也可以被讀取,稱為反序列化。
序列化
- 用 FileOutputStream 開啟檔案
- 用 ObjectOutputStream 將物件寫入 FileOutputStream
FileOutputStream fos = new FileOutputStream("filename");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object);
oos.flush(); // 立刻寫入檔案
oos.close();
反序列化
反序列化和序列化過程類似:
- 用 FileInputStream 開啟檔案
- 用 ObjectInputStream 從 FileInputStream 讀取物件
FileInputStream fis = new FileInputStream("filename");
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject(object);
ois.close();
自訂序列化
關於序列化有些小細節:
- 物件裡的 Field 若沒有實作 Serializable 會導致物件無法序列化
- 序列化時,有 static 或 transient 修飾詞的 Field 不會被寫入檔案
若想要將這些 Field 序列化,可以透過實作 Serializable 的方法來自訂序列化:
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private void writeObject(ObjectOutputStream oos)
throws IOException {
oos.defaultWriteObject();
oos.writeObject(grade.getChinese());
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
grade = new Grade((int) ois.readObject());
}
}
defaultWriteObject 和 defaultReadObject 是預設的序列化,後面就是自訂序列化了,把想要做的通通都寫在裡面就可以了。
SerialVersionUID
在上面的例子中,我為 Student 這個類別加入了 SerialVersionUID ,這個 UID 是用來驗證輸出和讀取的物件是指定的類別,若不是則會拋出 InvalidClassException 。
一般而言,IDE 會自動生成 UID ,若沒有指定 UID 則會由 JVM 指定。但是推薦手動指定,因為 UID 可能會因為編譯器而不同,導致產生 InvalidClassException 。