Java - 序列化

你好,未來的Java巫師們!今天,我們將進入Java序列化的奇幻世界。如果你是編程新手,不用擔心——我會成為你的友好嚮導,我們將一步一步來。在這個教程結束時,你將能像專家一樣序列化物件!

Java - Serialization

序列化是什麼?

在我們深入代碼之前,先來了解序列化實際上是什麼。想象一下,你有一個美味的三明治(在Java語境中是一個物件),你想透過郵局把它寄給你的朋友。你不可能直接把整個三明治塞進信封,對吧?相反,你需要把它拆解成各種食材,把它們寫在一张紙上,然後寄出。當你的朋友收到後,他可以使用這些指示重新做出三明治。這個將物件拆解成可以輕易存儲或傳輸的格式的過程稱為序列化。反向過程——從序列化數據中重新創建物件——稱為反序列化。

為什麼我们需要序列化?

序列化在Java中非常有用,原因有幾個:

  1. 儲存物件狀態:你可以儲存物件的状态並稍後重新創建它。
  2. 網絡通信:你可以將物件傳輸過網絡。
  3. 缓存:序列化物件可以存儲在緩存中以便快速訪問。
  4. 深度複製:它提供了一種創建物件深度複製的簡單方法。

現在,讓我們捲起袖子進入一些代碼!

序列化在Java中如何工作

在Java中,序列化是語言的內建功能,這讓我們的生活變得更加輕鬆。要使物件可序列化,我們需要做兩件事:

  1. 實現Serializable接口
  2. 確保物件的所有字段也都是可序列化的

讓我們創建一個簡單的Person類來演示:

import java.io.Serializable;

public class Person implements Serializable {
private String name;
private int age;

public Person(String name, int age) {
this.name = name;
this.age = age;
}

@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}

在這個例子中,Person實現了SerializableSerializable接口沒有任何方法——它只是一個標記接口,告訴Java這個類可以序列化。

序列化一個物件

現在我們有了Person類,讓我們序列化一個物件:

import java.io.*;

public class SerializationDemo {
public static void main(String[] args) {
Person person = new Person("Alice", 30);

try (FileOutputStream fileOut = new FileOutputStream("person.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
out.writeObject(person);
System.out.println("Person物件序列化並保存到person.ser");
} catch (IOException e) {
e.printStackTrace();
}
}
}

讓我們來解析一下:

  1. 我們創建了一個Person物件。
  2. 我們使用FileOutputStream來寫入名為"person.ser"的文件。
  3. 我們將FileOutputStream封裝在ObjectOutputStream中,該封裝負責實際的序列化。
  4. 我們調用writeObject()來序列化我們的Person物件。
  5. 我們使用try-with-resources語句來確保我們的流被正確關閉。

當你運行這個,它將創建一個名為"person.ser"的文件,其中包含序列化的Person物件。

反序列化一個物件

現在,讓我們反序列化我們的物件:

import java.io.*;

public class DeserializationDemo {
public static void main(String[] args) {
try (FileInputStream fileIn = new FileInputStream("person.ser");
ObjectInputStream in = new ObjectInputStream(fileIn)) {
Person person = (Person) in.readObject();
System.out.println("反序列化的Person物件:");
System.out.println(person);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}

以下是發生的事情:

  1. 我們使用FileInputStream從"person.ser"讀取。
  2. 我們將其封裝在ObjectInputStream中進行反序列化。
  3. 我們調用readObject()來反序列化物件,並將其強制轉換為Person
  4. 我們打印出反序列化的物件。

當你運行這個,你應該會看到原始的Person物件被打印出來!

關於Java序列化的重要點

  1. SerialVersionUID:為了序列化的版本控制,你可以在你的類中定義一個serialVersionUID
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
// ... 類的其餘部分
}
  1. 瞬時字段:如果你有不想序列化的字段(如敏感數據),請將它們標記為transient
public class Person implements Serializable {
private String name;
private int age;
private transient String password; // 這不會被序列化
// ... 類的其餘部分
}
  1. 自定義序列化:你可以通過在你的類中實現writeObject()readObject()方法來自定義序列化過程。

序列化和反序列化物件的方法

以下是用于序列化和反序列化的主要方法的表格:

方法 描述
ObjectOutputStream.writeObject(Object obj) 序列化一個物件
ObjectInputStream.readObject() 反序列化一個物件
Externalizable.writeExternal(ObjectOutput out) 自定義序列化方法
Externalizable.readExternal(ObjectInput in) 自定義反序列化方法

結論

恭喜你!你剛剛走出了Java序列化的第一步。我們已經涵蓋了序列化是什麼,為什麼它有用,以及如何在Java中實現它。請記住,練習成就完美,所以不要害怕對不同的物件和情節進行實驗。

當你繼續你的Java之旅時,你會發現序列化在不同的情境中出現——從儲存遊戲狀態到在網絡上傳輸數據。它是你編程工具箱中的一個強大工具。

繼續編碼,繼續學習,最重要的是,繼續玩得開心!誰知道呢,也許有一天你將會序列化整個虛擬世界。在那之前,快樂編碼!

Credits: Image by storyset