单例模式-枚举

那么现在再写一种最受欢迎的单例模式,即枚举单例模式。

枚举模式的代码如下:

date是为了测试方便。

public enum  EnumInstance {
    INSTANCE;
    private Object date;

    public Object getDate() {
        return date;
    }

    public void setDate(Object date) {
        this.date = date;
    }
    public static EnumInstance getInstance(){
        return INSTANCE;
    }
}

1、那么我们可以写一个序列化的栗子进行测试。

public class SerivalTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        EnumInstance instance = EnumInstance.getInstance();
        instance.setDate(new Object());
        //放文件
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("single_file"));
        outputStream.writeObject(instance);

        //取文件
        File file = new File("single_file");
        ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file));
        EnumInstance hungrySingleton = (EnumInstance) inputStream.readObject();

        System.out.println(instance);
        System.out.println(hungrySingleton);
        System.out.println(instance==hungrySingleton);
    }
}

 结果为:

 

怎么样?枚举就是这么强大,那么序列化和反序列化对枚举是怎么处理的呢?首先通过inputStream.readObject()进入,找到readEnum()方法。

如下:

是通过类型和name进行获得枚举常量,因为枚举中的name是唯一的,并且对应一个枚举常量,所以2012行拿到的肯定是唯一的常量对象,

这样呢就没有创建新的对象。维持了这个对象的单例属性。枚举中这个处理方法还是很简单的,而且很容易理解,所以枚举类对于序列化

这个破坏是不受影响的。

 

 

 2、写一个反射攻击的例子。

public class Testreflection {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class object = EnumInstance.class;
        Constructor constructor = object.getDeclaredConstructor();
        constructor.setAccessible(true);

        EnumInstance instance = EnumInstance.getInstance();
        EnumInstance newInstance = (EnumInstance) constructor.newInstance();

        System.out.println(instance.getDate());
        System.out.println(newInstance.getDate());
        System.out.println(instance.getDate() == newInstance.getDate());

     }
    }

看结果:

 

表示没有获得无参构造器,那么我们打开源码看一哈。java.lang.enum  可以看到枚举没有无参构造器,而且仅有一个传两个参数的构造器,如下所示。那么我们就将这两个参数传进去,再测试。

 

 

可以看到又抛了额一个异常,但是可以很清楚的了解到这个异常是说不能反射去创建对象,我们从报错的地方进入源码查看详情。

 

源码清清楚楚的告诉我们如果是枚举类型,就抛出异常,可见枚举是多么的强大!

 

posted @ 2020-04-10 22:41  左手背右手背  阅读(2189)  评论(0编辑  收藏  举报