設計模式-單例(Singleton)
阿新 • • 發佈:2018-01-12
don 設計模式 static sha 應用 ces zed void 內部類 2018-1-12 by Atlas
- UML
- UML中加“-”表示私有的(private);
- UML中加“+”表示公有的(public);
- UML中加“_”表示靜態的(static)。
Singleton模式基本構成:
- 靜態的私有的類成員變量singleton,私有的表示只有成員所生存的對象可以訪問,靜態的表示類加載準備階段分配初始值、解析階段字符引用轉化為直接引用;
- 私有的類構造方法Singleton,私有的構造方法表示禁止非Singleton類調用實例構造器創建對象實例;
- 靜態的公有的類方法getInstance,靜態的類方法表示類加載解析階段就從字符引用轉化為直接引用,即內存中方法的實際地址,可以通過類.方法直接調用。
- 應用場景
(1)如果有1個以上的對象實例時,由於對象實例彼此之間的影響,可能會發展成出乎意料的BUG。
(2)需要控制類的對象實例的數量,以降低資源的使用時。
- 標準示例
public class Singleton { private static Singleton singleton = new Singleton(); private Singleton() { System.out.println("已產生對象實例。"); } public static Singleton getInstance() { return singleton; } } public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); System.out.println(s1 == s2); }
- 拓展示例
延遲對象實例化
- 優點:
類加載時不進行目標對象的實例化操作,提高了類加載的速度,實際訪問需要時才進行目標對象的實例化。- 缺點:
相比類加載時就進行目標對象實例化,延遲實例化可能導致多線程並發時產生線程安全問題,需要同步訪問入口方法以達到線程安全的目的,理論上降低了多線程並發訪問的效率。
public class Singleton { private static Singleton singleton; private Singleton() { System.out.println("已產生對象實例。"); } public static synchronized Singleton getInstance() { if(singleton == null){ singleton = new Singleton(); } return singleton; } } public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); System.out.println(s1 == s2); }
那麽問題來了,有沒有一種兩全其美的方式呢,答案是有的。
靜態內部類實例化
- 優點:
(1)外部類加載時無須進行目標對象的實例化操作,提高了類加載的速度,實際訪問需要時加載內部類並進行目標對象的實例化。
(2)靜態內部類只會進行一次內部類的類變量的初始化,不會產生線程安全問題,無須同步,不會降低多線程並發訪問效率。
public class Singleton {
private Singleton() {
System.out.println("已產生對象實例。");
}
private static class SingletonHolder {
private static Singleton singleton = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.singleton;
}
}
- 案例鑒賞
java.lang.Runtime#getRuntime()
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don‘t let anyone else instantiate this class */
private Runtime() {}
// 忽略其他
}
設計模式-單例(Singleton)