一、什麼是Singleton?
Singleton 指的是僅僅隻能被執行個體化一次的類。(通常用來代表本質上唯一的系統元件:視窗管理器,檔案系統)
二、Java 1.5 之前的兩種實作方法
把
構造器保持為私有的
,然後導出
公有的靜态成員
(
public static
),允許用戶端通路這個類的唯一的執行個體。私有的構造器(
private Dog(){...}
)僅會被調用一次去進行執行個體化,這保證了類隻能被執行個體化一次;
- 公有的靜态成員是一個
(調用:final域
)Dog.INSTANCE
//Singleton with public final field
public class Dog {
//公有靜态執行個體(final域保持執行個體唯一)
public static final Dog INSTANCE = new Dog();
//私有的構造器
private Dog() {...}
public void sleep() {...}
}
- 公有的靜态成員是一個
(調用:靜态工廠方法
)Dog.getInstance
//Singleton with static factory
public class Dog {
//公有靜态執行個體(final域保持執行個體唯一)
public static final Dog INSTANCE = new Dog();
//私有的構造器
private Dog() {...}
//靜态方法
public static Dog getInstance() {return INSTANCE;}
public void sleep() {...}
//readResolve方法,保證signleton的實作
private Object readResolve() {
//傳回真執行個體,并讓垃圾回收器處理假執行個體
return INSTANCE;
}
}
一般都會使用第二種方法,調用靜态方法
Dog.getInstance
,每次調用都會傳回同一個對象引用,是以保持了執行個體的唯一性。
注意:
- public 和 private 的構造器可以多次調用;
- 享有特權的用戶端可以借助
方法,通過反射機制來調用私有構造器。(抵禦方法:修改構造器,在第二次被調用時抛異常)AccessibleObject.setAccessible
- 為了實作序列化,隻implement Serializabled是不夠的,還得聲明所有執行個體域都是瞬時(transent,文末有解釋)的,并在Dog類裡提供一個
方法。否則,每次反序列化的時候,都會新建立一個執行個體(假冒的Dog類)readResolve
三、java 1.5之後 —— 最佳實作方法(enum)
- 編寫一個包含
,而不是class類單個元素的枚舉類型enum
//Enum singleton - the preferred approach
public enum Dog {
INSTANCE;
public void sleep () {...}
}
這種方法在功能上與公有域方法相近,但更加簡潔,提供了
序列化機制
,即使面對複雜的序列化或者發射攻擊,也絕對防止了多次執行個體化。
瞬時(transient):
一個持久化類的執行個體可能處于三種不同的狀态中的某一種。這三種狀态的定義則與所謂的持久化上下文(persistence context)有關。Hibernate的Session對象就是這個所謂的持久化上下文。
瞬态(transient)
該執行個體從未與任何持久化上下文關聯過。它沒有持久化辨別(相當于主鍵值)。
持久化(persistent)
執行個體目前與某個持久化上下文有關聯。它擁有持久化辨別(相當于主鍵值),并且可能在資料庫中有一個對應的行。對于某一特定的持久化上下文,Hibernate保證持久化辨別與Java辨別(其值代表對象在記憶體中的位置)等價。
托管(detached)
執行個體曾經與某個持久化上下文發生過關聯,不過那個上下文被關閉了,或者這個執行個體是被序列化(serialize)到另外的程序。它擁有持久化辨別,并且在資料庫中可能存在一個對應的行。對于托管狀态的執行個體,Hibernate不保證任何持久化辨別和Java辨別的關系。
參考1、《Effictive Java》