枚举的本质
- 枚举本质是一个类,使用设计模式中的
单例模式
,但是不可以被反射创建
public enum EnumDeep {
APPLE("红", 19.23),
ORANGE("橙红", 200.01);
EnumDeep(String color, double money) {}
}
很简单的一个枚举类
- Constructor源码中newInstance方法调用newInstanceWithCaller方法,如果是枚举就会抛出异常
@CallerSensitive
@ForceInline // to ensure Reflection.getCallerClass optimization
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
Class<?> caller = override ? null : Reflection.getCallerClass();
return newInstanceWithCaller(initargs, !override, caller);
}
T newInstanceWithCaller(Object[] args, boolean checkAccess, Class<?> caller)
throws InstantiationException, IllegalAccessException,
InvocationTargetException
{
if (checkAccess)
checkAccess(caller, clazz, clazz, 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(args);
return inst;
}
为了保证单例模式的安全性。
反射创建枚举抛出异常
Constructor<?>[] c = EnumDeep.class.getDeclaredConstructors();
for (Constructor<?> constructor : c) {
System.out.println(constructor);
constructor.setAccessible(true); // 允许访问private
constructor.newInstance();
}
// 报错: Cannot reflectively create enum objects
与上面Constructor源码报错信息一致。所以枚举类是单例模式最安全的,不会被反射破解,我们自己写的DCL懒汉模式会被反射破解。