重学Java之单例模式--枚举

接上篇重学Java之单例模式–DCL懒汉式_南国樗里疾的博客-CSDN博客
https://blog.csdn.net/weixin_44021334/article/details/114881148 ,

DCL懒汉式单例,容易被反射破坏,
看下 Constructor.newInstance 方法,提示如果枚举则抛出异常 "Cannot reflectively create enum objects"

@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;
    }

那么我们就用枚举来试试。

1.正常创建

package single;

public enum EnumSingle {

    ENUM_SINGLE_INSTANCE;

    public static EnumSingle getInstance(){
        return ENUM_SINGLE_INSTANCE;
    }
}

class TestEnum{

    public static void main(String[] args) {
        EnumSingle enumSingle1 = EnumSingle.getInstance();
        EnumSingle enumSingle2 = EnumSingle.getInstance();

        System.out.println("enumSingle1 = " + enumSingle1);
        System.out.println("enumSingle2 = " + enumSingle2);
    }
}

运行结果,两个是一样的。

2.反射创建

package single;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public enum EnumSingle {

    ENUM_SINGLE_INSTANCE;

    public static EnumSingle getInstance(){
        return ENUM_SINGLE_INSTANCE;
    }
}

class TestEnum{

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        EnumSingle enumSingle1 = EnumSingle.getInstance();
        EnumSingle enumSingle2 = EnumSingle.getInstance();

        System.out.println("enumSingle1 = " + enumSingle1);
        System.out.println("enumSingle2 = " + enumSingle2);
		
		// 方法1
        /*Constructor constructor = EnumSingle.class.getDeclaredConstructor(null);
        constructor.setAccessible(true);
        EnumSingle enumSingle3 = constructor.newInstance();
        EnumSingle enumSingle4 = constructor.newInstance();*/
		
		// 方法2
        Constructor constructor2 = EnumSingle.class.getDeclaredConstructor(String.class, int.class);
        constructor2.setAccessible(true);
        EnumSingle enumSingle5 = constructor2.newInstance();
        EnumSingle enumSingle6 = constructor2.newInstance();
    }
}

方法1报错,不是开篇提示的报错,

Exception in thread "main" java.lang.NoSuchMethodException: single.EnumSingle.()
	at java.lang.Class.getConstructor0(Class.java:3074)
	at java.lang.Class.getDeclaredConstructor(Class.java:2170)
	at single.TestEnum.main(EnumSingle.java:24)

方法2报错,正是开篇提示的报错,

Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:402)
	at single.TestEnum.main(EnumSingle.java:31)

可以看到,反射无法破坏枚举的单例。
有个疑问,方法1、方法2 传入的参数不一致,一个是空的构造方法,一个是带参数的构造方法,为什么方法2才是源码里的报错?

你可能感兴趣的:(Java,设计模式,java,设计模式,单例模式,枚举类)