枚舉實現(xiàn)單例模式
前面我們說到序列化和反序列化以及反射對單例都是有破壞的嗦哆,下面我們介紹一種更加優(yōu)雅的實現(xiàn)燕鸽,也是effective java中推薦的實現(xiàn)方式,枚舉實現(xiàn)單例模式敬拓。話不多說我們直接看代碼吧邻薯。
public enum EnumInstance {
INSTANCE{
protected void printTest(){
System.out.println("redstar Print SingletonTest");
}
};
protected abstract void printTest();
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumInstance getInstance(){
return INSTANCE;
}
}
然后我們看看測試類
public class SingletonTest {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
EnumInstance instance = EnumInstance.getInstance();
instance.setData(new Object());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
oos.writeObject(instance);
File file = new File("singleton_file");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
EnumInstance newInstance = (EnumInstance) ois.readObject();
System.out.println(instance.getData());
System.out.println(newInstance.getData());
System.out.println(instance.getData() == newInstance.getData());
}
這里返回的結果是true,然后我們測試一下反射去獲取這個對象乘凸。
public class SingletonTest {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class objectClass = EnumInstance.class;
Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
EnumInstance instance = (EnumInstance) constructor.newInstance("redstar",666);
}
運行結果報異常
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
我們點擊進去查看一下417行的代碼
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor;
從這里我們可以看到jdk底層就為我們對反射進行處理了厕诡。