Talk is cheap Show me the code
個人學習筆記--僅供參考
註冊式單例
註冊式單例又稱爲登記式單例,就是將每一個實例都登記到某一個地方,使用唯一的標
識獲取實例
註冊式單例有兩種寫法:一種爲容器緩存,一種爲枚舉登記
枚舉
package pattern;
/**
* 註冊式單例又稱爲登記式單例,就是將每一個實例都登記到某一個地方,使用唯一的標
識獲取實例。註冊式單例有兩種寫法:一種爲容器緩存,一種爲枚舉登記。先來看枚舉
式單例的寫法,來看代碼
* @author qsnp236
*
*/
public enum EnumSingleton{
// 餓漢
HUNGARY("hungary"),
// 懶漢
LAZY("lazy"),
// 內部類
INNERCLASS("inner_class");
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
EnumSingleton(String name){
this.name=name;
}
public static EnumSingleton getInstance(String desc) {
for (EnumSingleton configType : EnumSingleton.values()){
if (configType.getName().equals(desc)){
return configType;
}
}
throw new IllegalArgumentException("無法轉化爲對應的enum類型,原因是未知描述信息: " + desc);
}
}
測試類
package pattern;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class EnumSingletonTest {
public static void main(String[] args) {
EnumSingleton s1=EnumSingleton.getInstance("lazy");
FileOutputStream fos;
try {
fos = new FileOutputStream("EnumSingleton.obj");
ObjectOutputStream os= new ObjectOutputStream(fos);
os.writeObject(s1);
os.flush();
os.close();
FileInputStream fis= new FileInputStream("EnumSingleton.obj");
ObjectInputStream ois= new ObjectInputStream(fis);
EnumSingleton s2=(EnumSingleton) ois.readObject();
ois.close();
System.out.println(s1);
System.out.println(s2);
System.out.println(s1.getName());
System.out.println(s2.getName());
System.out.println(s1==s2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
測試結果
LAZY
LAZY
lazy
lazy
true
底層代碼
static
{
INSTANCE = new EnumSingleton("INSTANCE", 0);
$VALUES = (new EnumSingleton[] {
INSTANCE
});
}
原來,枚舉式單例在靜態代碼塊中就給INSTANCE 進行了賦值,是餓漢式單例的實現,
序列化和反序列化中,我們發現枚舉類型其實通過類名和Class 對象類找到一個唯一的枚舉對象。因此,枚舉對
象不可能被類加載器加載多次,反射中,在newInstance()方法中做了強制性的判斷,如果修飾符是Modifier.ENUM 枚舉類型,
直接拋出異常
接下來看註冊式單例還有另一種寫法,容器緩存的寫法,創建ContainerSingleton 類
package pattern;
import java.io.Serializable;
import java.nio.file.SecureDirectoryStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 容器式寫法適用於創建實例非常多的情況,便於管理。但是,是非線程安全的。比如spring IOC 容器
*
* @author qsnp236
*
*/
public class ContainerSingleton implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private ContainerSingleton() {
}
private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();
public static Object getBean(String className) {
synchronized (ioc) {
if (!ioc.containsKey(className)) {
Object obj = null;
try {
Class<?> clazz = Class.forName(className);
obj = clazz.newInstance();
ioc.put(className, obj);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return obj;
} else {
return ioc.get(className);
}
}
}
}