第3條 用私有構造器或者枚舉類型強化Singleton屬性

Singleton一般被用來表明那些本質上惟一的系統組件,在JDK1.5以前,實現Singleton有兩種方法。這兩種方法都要把構造器保持爲私有的,並導出公有的靜態成員,以便容許客戶端可以訪問該類的惟一實現。java

第一種方式:1.構造器私有,2,有一個公共的靜態成員,而且是final的。多線程

public class Singleton {
     
    private Singleton(){
        //在此將構造函數設置爲private,防止該類在外部被實例化
    }

    public static final Singleton Instance = new Singleton();
     
    public void test(){
        System.out.println("Test...");
    }
 
}

構造方法私有化的做用:外面調用只能調用類的靜態函數,而不能new去建立對象;私有構造函數只能在函數內部調用,外部不能實例化,因此私有構造函數能夠防止該類在外部被實例化。不過享有特v權的客戶端能夠藉助AccessibleObject.setAccessible()方法,經過反射機制調用私有構造器。若是須要抵禦這種攻擊,能夠修改構造器,讓他在被要求建立的第二個實例時候拋出異常。  函數

第二種方式:1,構造器私有,2,有一個私有的靜態成員,可是有一個公共的靜態工廠方法  spa

public class Singleton1 {
     
    private static final Singleton1 INSTANCE = new Singleton1();
     
    private Singleton1(){}
     
    public static Singleton1 getInstance(){
        return INSTANCE;
    }
     
    public void test(){
        System.out.println("Test...");
    }
     
 
}

這就是傳說中的懶漢式的單例模式,通常狀況下,爲了防止多線程的時候建立多個實例,都會加上synchronized 關鍵字。線程

對於靜態方法getInstance()方法的全部調用,都會返回同一個對象的應用。這種寫法的好處是很清楚地代表了該類是一個Singleton,可是這種寫法有另外一個好處是,能夠添加其餘的靜態工廠方法返回另外一個新的實例,這樣就能夠將該類變爲非Signleton。爲了使利用上述方法實現Singleton類變成是可序列化的,僅僅在聲明時加上「implements Serializable」是不夠的。爲了維護並保證Singleton,必須聲明全部實例都是瞬時transient的,並提供 一個readResolve方法。不然每次反序列化一個序列化的實例時,都會建立一個新的實例。即會致使一個假冒的對象。爲了防止這種狀況,須要在單例類中增長readResolve方法。延伸以下:code

public class Singleton implements Serializable {

 	public static final Singleton INSTANCE = new Singleton();

	private Singleton() {
	}
	private Object readResolve() {
	// Return the one true Elvis and let the garbage collector
	// take care of the Elvis impersonator.
	return INSTANCE;
	}

}

實現Singleton還有第三種方法,從JDK1.5開始,只需編寫一個包含單個元素的枚舉類型。推薦的寫法:對象

public enum Singleton3 {
    INSTANCE;
     
    public void test(){
        System.out.println("test...");
    }
 
}

這種方法在功能上與公有域接近,可是它更簡潔。雖然這種方法尚未普遍採用,可是單元素的枚舉類型已經成爲實現Singleton的最佳方法。get

相關文章
相關標籤/搜索