设计模式|单例模式(3) Enum枚举单例

上篇文章已经讨论了单例模式的安全问题。而枚举类型的单例模式是实现单例模式的最好的方法

参考:《Effective Java中文版》 p14-p15

只需编写一个包含单个元素的枚举类型。

代码

枚举类

public enum EnumSingleton {
    INSTANCE;
    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance(){
        return INSTANCE;
    }

}

测试类

/**
 * 枚举类型的单例模式测试
 */
@org.junit.Test
public void test08(){
    EnumSingleton enumSingleton = EnumSingleton.getInstance();
    enumSingleton.setData("we");
    System.out.println(enumSingleton); // INSTANCE
    EnumSingleton enumSingleton1 = EnumSingleton.getInstance();
    System.out.println(enumSingleton1); // INSTANCE
    System.out.println(enumSingleton1.getData()); //we
    System.out.println(enumSingleton == enumSingleton1); //true
}

反序列化攻击测试

/**
 * 枚举类型的单例模式测试:反序列化攻击
 */
@org.junit.Test
public void test09() throws Exception{
    /**
     * 正常获取实例
     */
    EnumSingleton enumSingleton = EnumSingleton.getInstance();
    enumSingleton.setData("we");
    System.out.println(enumSingleton.getData()); // we

    /**
     * 反序列化获取实例
     */
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("enumSingleten"));
    oos.writeObject(enumSingleton);
    File file = new File("enumSingleten");
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
    EnumSingleton newInstance = (EnumSingleton)ois.readObject();
    System.out.println(newInstance.getData()); // we
    /**
     * 比较
     */
    System.out.println(newInstance.getData() == enumSingleton.getData());//true
}

同一个实例

反射攻击实例

/**
 * 枚举类型的单例模式测试:反射攻击
 */
@org.junit.Test
public void test10() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    /**
     * 正常获取实例
     */
    EnumSingleton enumSingleton = EnumSingleton.getInstance();
    enumSingleton.setData("we");
    System.out.println(enumSingleton.getData());

    /**
     * 反射获取实例
     */
    Class<EnumSingleton> enumSingletonClass = EnumSingleton.class;
    Constructor<EnumSingleton> constructor = enumSingletonClass.getDeclaredConstructor(String.class,int.class);
    constructor.setAccessible(true);
    /**
     * 如果newInstance()方法没有参数java.lang.NoSuchMethodException
     * 具体可看反射对枚举类型的处理方式
     */
    /**
     * 报错:
     * java.lang.IllegalArgumentException: Cannot reflectively create enum objects
     * 不能反射enum类型
     */
    EnumSingleton newInstance = constructor.newInstance("we",1);
    System.out.println(newInstance.getData());
 }

通过上面可以看到枚举类型可以防止反射攻击。

扩展1:在枚举类中声名方法

枚举类

public enum EnumSingleton{
    INSTANCE{
        protected void printTest(){
            System.out.println("test");
        }
    };
    protected abstract void printTest();
 }

测试

/**
 * 枚举类调用方法
 */
@org.junit.Test
public void test11(){
    EnumSingleton enumSingleton = EnumSingleton.getInstance();
    enumSingleton.printTest();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值