0. 前言
在Java對象的創(chuàng)建時,單例模式使用尤其多,同時也是個面試必問的基礎(chǔ)題。很多時候面試官想問的無非是懶漢式的雙重檢驗鎖。但是其實還有兩種更加直觀高效的寫法,也是《Effective Java》中所推薦的寫法。
1. 靜態(tài)內(nèi)部類(static nested class)
public class Singleton {
public static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
由于靜態(tài)內(nèi)部類SingletonHolder只有在getInstance()方法第一次被調(diào)用時,才會被加載,而且構(gòu)造函數(shù)為private,因此該種方式實現(xiàn)了懶漢式的單例模式。不僅如此,根據(jù)JVM本身機制,靜態(tài)內(nèi)部類的加載已經(jīng)實現(xiàn)了線程安全。所以給大家推薦這種寫法。
2. 枚舉法(Enum)
在《Effective Java》最后推薦了這樣一個寫法,簡直有點顛覆,不僅超級簡單,而且保證了線程安全。這里引用一下,此方法無償提供了序列化機制,絕對防止多次實例化,及時面對復雜的序列化或者反射攻擊。單元素枚舉類型已經(jīng)成為實現(xiàn)Singleton的最佳方法。
public enum Singleton {
INSTANCE;
}
3. 枚舉法探究
很多人會對枚舉法實現(xiàn)的單例模式很不理解。這里需要深入理解的是兩個點:
- 枚舉類實現(xiàn)其實省略了
private類型的構(gòu)造函數(shù) - 枚舉類的域(field)其實是相應(yīng)的enum類型的一個實例對象
對于第一點實際上enum內(nèi)部是如下代碼:
public enum Singleton {
INSTANCE;
// 這里隱藏了一個空的私有構(gòu)造方法
private Singleton () {}
}
對于一個標準的enum單例模式,最優(yōu)秀的寫法還是實現(xiàn)接口的形式:
// 定義單例模式中需要完成的代碼邏輯
public interface MySingleton {
void doSomething();
}
public enum Singleton implements MySingleton {
INSTANCE {
@Override
public void doSomething() {
System.out.println("complete singleton");
}
};
public static MySingleton getInstance() {
return Singleton.INSTANCE;
}
}
到這里,相信各位同學一定非常明白了。以后寫讓人眼前一亮的effective code吧~
4. 一些資料
以下列舉了枚舉法探究的一些很好的鏈接,強烈建議讀者點進去用心體會一下。