寫在前面
單例設(shè)計模式赎瞎,相信是大家接觸設(shè)計模式時的入門設(shè)計模式牌里,它理解起來比較簡單颊咬,當(dāng)然實現(xiàn)起來也很簡單务甥,但是別看不上這簡單的東西牡辽,簡單的事情重復(fù)做將不再簡單,再復(fù)雜的事情拆分開來也是由很多簡單的事情的集合敞临。接下來來過一遍三種經(jīng)典的單例模式态辛。
單例模式三個主要特點(diǎn):
- 1、構(gòu)造方法私有化挺尿;
- 2奏黑、實例化的變量引用私有化;
- 3编矾、獲取實例的方法共有熟史。
1、雙重否定單例模式
public class DCLSingleton implements Serializable {
private static final long serialVersionUID = 6242241249985894658L;
/**
* volatile :內(nèi)存中可見 和 防止指令重排
* 這里主要作用是防止指令重排
*/
private volatile static DCLSingleton instance;
private DCLSingleton() {
}
public static DCLSingleton getInstance() {
if (instance == null) {
synchronized (DCLSingleton.class) {
if (instance == null) {
instance = new DCLSingleton();
}
}
}
return instance;
}
public void singletonFunction() {
System.out.println("DCLSingleton test.");
}
}
2窄俏、登記式/靜態(tài)內(nèi)部類單例模式
public class StaticSingleton implements Serializable {
private static final long serialVersionUID = 5537012394799626447L;
private static class SingletonHolder {
private static final StaticSingleton INSTANCE = new StaticSingleton();
}
private StaticSingleton(){}
public static final StaticSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
public void singletonFunction() {
System.out.println("StaticSingleton test.");
}
}
3蹂匹、枚舉單例模式
public enum SingletonEnum {
/**
* 實例
*/
INSTANCE;
/**
* 方法
*/
public void singletonFunction() {
System.out.println("SingletonEnum test.");
}
}
測試
以單例性和安全性 2 個方向?qū)σ陨?3 種單例模式進(jìn)行測試,看哪種比較適合
1凹蜈、序列化和反序列化測試單例性
public class TestSerializable {
public static void main(String[] args) throws IOException, ClassNotFoundException {
System.out.println("----------------雙重否定單例模式測試開始-----------------------------");
DCLSingleton instance_1 = DCLSingleton.getInstance();
ByteArrayOutputStream byteArrayOutputStream_1 = new ByteArrayOutputStream();
new ObjectOutputStream(byteArrayOutputStream_1).writeObject(instance_1);
ObjectInputStream objectInputStream_1 = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream_1.toByteArray()));
DCLSingleton singleton_1 = (DCLSingleton) objectInputStream_1.readObject();
//com.songo.singletonpattern.service.SingletonPattern1@27c170f0
System.out.println(instance_1);
//com.songo.singletonpattern.service.SingletonPattern1@3d494fbf
System.out.println(singleton_1);
//DCLSingleton test.
singleton_1.singletonFunction();
//序列化和反序列化后是否相同:false
System.out.println("序列化和反序列化后是否相同:" + (instance_1 == singleton_1));
System.out.println("----------------雙重否定單例模式測試結(jié)束-----------------------------");
System.out.println("----------------靜態(tài)內(nèi)部類單例模式測試開始---------------------------");
StaticSingleton instance_2 = StaticSingleton.getInstance();
ByteArrayOutputStream byteArrayOutputStream_2 = new ByteArrayOutputStream();
new ObjectOutputStream(byteArrayOutputStream_2).writeObject(instance_2);
ObjectInputStream objectInputStream_2 = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream_2.toByteArray()));
StaticSingleton singleton_2 = (StaticSingleton) objectInputStream_2.readObject();
//com.songo.singletonpattern.service.StaticSingleton@7cd84586
System.out.println(instance_2);
//com.songo.singletonpattern.service.StaticSingleton@30dae81
System.out.println(singleton_2);
//StaticSingleton test.
singleton_2.singletonFunction();
//序列化和反序列化后是否相同:false
System.out.println("序列化和反序列化后是否相同:" + (instance_2==singleton_2));
System.out.println("----------------靜態(tài)內(nèi)部類單例模式測試結(jié)束---------------------------");
System.out.println("----------------枚舉單例模式測試結(jié)束---------------------------------");
SingletonEnum instance_3 = SingletonEnum.INSTANCE;
ByteArrayOutputStream byteArrayOutputStream_3 = new ByteArrayOutputStream();
new ObjectOutputStream(byteArrayOutputStream_3).writeObject(instance_3);
ObjectInputStream objectInputStream_3 = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream_3.toByteArray()));
SingletonEnum singleton_3 = (SingletonEnum) objectInputStream_3.readObject();
//INSTANCE
System.out.println(instance_3);
//INSTANCE
System.out.println(singleton_3);
//SingletonEnum test.
singleton_3.singletonFunction();
//序列化和反序列化后是否相同:true
System.out.println("序列化和反序列化后是否相同:" + (instance_3==singleton_3));
System.out.println("----------------枚舉單例模式測試結(jié)束---------------------------------");
}
}
由程序結(jié)果可知枚舉單例模式通過序列化和反序列化操作后對象沒有改變限寞,單例性夠強(qiáng),此處枚舉單例模式完勝
2仰坦、通過反射測試安全性
public class Testreflect {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
System.out.println("----------------雙重否定單例模式測試開始-----------------------------");
DCLSingleton instance_1 = DCLSingleton.getInstance();
Constructor constructor_1 = DCLSingleton.class.getDeclaredConstructor();
constructor_1.setAccessible(true);
DCLSingleton newInstance_1 = (DCLSingleton) constructor_1.newInstance();
//com.songo.singletonpattern.service.SingletonPattern1@4d7e1886
System.out.println(instance_1);
//com.songo.singletonpattern.service.SingletonPattern1@3cd1a2f1
System.out.println(newInstance_1);
//DCLSingleton test.
newInstance_1.singletonFunction();
//通過反射得到的對象和原來是否相同:false
System.out.println("通過反射得到的對象和原來是否相同:" + (instance_1 == newInstance_1));
System.out.println("----------------雙重否定單例模式測試結(jié)束-----------------------------");
System.out.println("----------------靜態(tài)內(nèi)部類單例模式測試開始---------------------------");
StaticSingleton instance_2 = StaticSingleton.getInstance();
Constructor constructor_2 = StaticSingleton.class.getDeclaredConstructor();
constructor_2.setAccessible(true);
StaticSingleton newInstance_2 = (StaticSingleton) constructor_2.newInstance();
//com.songo.singletonpattern.service.SingletonPattern2@2f0e140b
System.out.println(instance_2);
//com.songo.singletonpattern.service.SingletonPattern2@7440e464
System.out.println(newInstance_2);
//StaticSingleton test.
newInstance_2.singletonFunction();
//通過反射得到的對象和原來是否相同:false
System.out.println("通過反射得到的對象和原來是否相同:" + (instance_2 == newInstance_2));
System.out.println("----------------靜態(tài)內(nèi)部類單例模式測試結(jié)束---------------------------");
System.out.println("----------------枚舉單例模式測試開始---------------------------------");
//枚舉沒有無參構(gòu)造方法履植,這里加上參數(shù)
SingletonEnum instance_3 = SingletonEnum.INSTANCE;
Constructor constructor_3 = SingletonEnum.class.getDeclaredConstructor(String.class,int.class);
constructor_3.setAccessible(true);
//異常 Cannot reflectively create enum objects
SingletonEnum newInstance_3 = (SingletonEnum) constructor_3.newInstance("test",111);
System.out.println(instance_3);
System.out.println(newInstance_3);
newInstance_3.singletonFunction();
System.out.println(instance_3 == newInstance_3);
System.out.println("----------------枚舉單例模式測試結(jié)束---------------------------------");
}
由程序結(jié)果可知枚舉單例模式?jīng)]有無參的構(gòu)造方法,即使構(gòu)造有參的構(gòu)造方法反射也不通過悄晃,報異常 Cannot reflectively create enum objects 玫霎,安全性夠強(qiáng),此處枚舉單例模式完勝
代碼詳情可參考源碼妈橄,github:https://github.com/charmsongo/songo-code-samples/tree/master/singleton-pattern
如果有哪些不對的地方煩請指認(rèn)鼠渺,先行感謝