Enum枚举单例
- 实现单例的核心在于private私有化类中的构造方法,在枚举中的构造方法必须是私有的,这就为枚举来实现单例奠定了基础。
-
枚举类天然的可序列化机制,能够保证不会出现多次实例化的情况。
序列化是否破坏单例模式测试代码
public enum EnumInstance {
INSTANCE;
public static EnumInstance getInstance() {
return INSTANCE;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
private Object data;
}
Test测试,输出的同一个对象
EnumInstance enumInstance=EnumInstance.getInstance();
File file=new File("singlton");
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(file));
objectOutputStream.writeObject(enumInstance);
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
EnumInstance newEnumInstance= (EnumInstance) objectInputStream.readObject();
System.out.println(enumInstance);
System.out.println(newEnumInstance);
System.out.println(enumInstance==newEnumInstance);
原因
Java规范中规定,每一个枚举类型极其定义的枚举变量在JVM中都是唯一的,因此在枚举类型的序列化和反序列化上,Java做了特殊的规定。
在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过 java.lang.Enum 的 valueOf() 方法来根据名字查找枚举对象。所以对象是同一个对象
反射是否破坏单例模式测试代码
改写Test代码
Class objectClass=EnumInstance.class;
Constructor constructor=objectClass.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
EnumInstance enumInstance=EnumInstance.getInstance();
EnumInstance newEnumInstance= (EnumInstance) constructor.newInstance();
System.out.println(enumInstance);
System.out.println(newEnumInstance);
System.out.println(enumInstance==newEnumInstance);
执行会报异常
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
at com.pattern.create.sigleton.Test.main(Test.java:47)
看一下Constructor源码,可以看到对枚举类型进行了判断,不允许反射创建对象
@CallerSensitive
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}
枚举类是如何做到线程安全的呢