如何在 Java 中序列化單例
瀏覽人數:267最近更新:
一、概述
在本快速教程中,我們將學習如何在 Java 中創建可序列化的單例類。
2.什麼是連載?
序列化是將 java 對象的狀態轉換為可以存儲在文件或數據庫中的字節流的過程:
反序列化則相反。它從字節流創建對象:
3.可Serializable
接口
Serializable
接口是一個標記接口(也稱為標記接口)。標記接口為編譯器和 JVM 提供有關對象的運行時類型信息。它內部沒有任何字段、方法或常量。因此實現它的類不必實現任何方法。
如果一個類實現了Serializable
接口,它的實例就可以被序列化或反序列化。
4. 什麼是單例類?
在面向對象編程中,單例類是一次只能有一個實例的類。在第一次實例化之後,如果我們嘗試再次實例化單例類,它會為我們提供與第一次創建的實例相同的實例。這是一個實現了Serializable
接口的單例類:
public class Singleton implements Serializable {
private static Singleton INSTANCE;
private String state = "State Zero";
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
我們可以看到它有兩個私有字段: INSTANCE
和state
.
INSTANCE
是單例類的唯一實例, state
是一個保存類狀態的字符串變量。
5. 創建可序列化的單例類
問題是,在實例化一個實現Serializable
的單例類之後,然後對該實例進行序列化和反序列化,我們最終會得到單例類的兩個實例,這違反了單例性:
@Test
public void givenSingleton_whenSerializedAndDeserialized_thenStatePreserved() {
Singleton s1 = Singleton.getInstance();
s1.setState("State One");
try (
FileOutputStream fos = new FileOutputStream("singleton_test.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
FileInputStream fis = new FileInputStream("singleton_test.txt");
ObjectInputStream ois = new ObjectInputStream(fis)) {
// Serializing.
oos.writeObject(s1);
// Deserializing.
Singleton s2 = (Singleton) ois.readObject();
// Checking if the state is preserved.
assertEquals(s1.getState(), s2.getState());
// Checking if s1 and s2 are not the same instance.
assertNotEquals(s1, s2);
} catch (Exception e) {
// ...
}
}
以上測試代碼通過。因此,即使在序列化和反序列化期間保留了狀態,新變量s2
也不會指向與s1
相同的實例。所以Singleton
類有兩個實例,這樣不好。
要創建可序列化的單例類,我們應該使用枚舉單例模式:
public enum EnumSingleton {
INSTANCE("State Zero");
private String state;
private EnumSingleton(String state) {
this.state = state;
}
public EnumSingleton getInstance() {
return INSTANCE;
}
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
}
現在讓我們看看如果我們序列化和反序列化它會發生什麼:
@Test
public void givenEnumSingleton_whenSerializedAndDeserialized_thenStatePreserved() {
EnumSingleton es1 = EnumSingleton.getInstance();
es1.setState("State One");
try (
FileOutputStream fos = new FileOutputStream("enum_singleton_test.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
FileInputStream fis = new FileInputStream("enum_singleton_test.txt");
ObjectInputStream ois = new ObjectInputStream(fis)) {
// Serializing.
oos.writeObject(es1);
// Deserializing.
EnumSingleton es2 = (EnumSingleton) ois.readObject();
// Checking if the state is preserved.
assertEquals(es1.getState(), es2.getState());
// Checking if es1 and es2 are pointing to
// the same instance in memory.
assertEquals(es1, es2);
} catch (Exception e) {
// ...
}
}
以上測試代碼通過。因此,在序列化和反序列化之後狀態被保留,並且兩個變量es1
和es2
指向最初創建的同一個實例。
6.總結
在本教程中,我們學習瞭如何在 Java 中創建可序列化的單例類。
一如既往,完整的代碼示例可在 GitHub 上獲得。
本作品係原創或者翻譯,採用《署名-非商業性使用-禁止演繹4.0國際》許可協議