java设计模式一创建型模式一单例模式一反射破坏单例模式和其解决方法

想要破坏单例模式,可以在定义的单例类Singleton创建多个对象.枚举方式除外,还有两种方式,序列化和反射.上篇我们讲了序列化,这篇我们来看看反射.不知道反射的可以点击以下链接进行学习http://t.csdn.cn/ppwvZ
单例模式代码:
public class Singleton1 {

//私有构造方法
private Singleton1(){
    
}
//定义一个静态内部类
private static class SingletonHolder{
    //在内部类中声明并初始化外部类的对象
    private static final Singleton1 INSTANCE = new Singleton1();
}
//提供公共的访问方式
public static Singleton1 getInstance(){
    return Singleton1.SingletonHolder.INSTANCE;
}

//当进行反序列化时,会自动调用该方法,将该方法的返回值直接返回
public Object readResolve(){
    return Singleton1.SingletonHolder.INSTANCE;
}

}

测试类,反射破坏单例模式代码:
import java.lang.reflect.Constructor;

public class Client1 {
public static void main(String[] args) throws Exception{
//1,获取Singleton的字节码对象
Class clazz = Singleton1.class;
//2,获取无参构造方法对象
Constructor constructor = clazz.getDeclaredConstructor();
//3,取消访问检查
constructor.setAccessible(true);
//4,创建Singleton对象
Singleton1 singleton1 = (Singleton1) constructor.newInstance();
Singleton1 singleton2 = (Singleton1) constructor.newInstance();

    System.out.println(singleton1==singleton2);//如果返回true,没有破坏单例模式,如果返回false,破坏单例模式.


}

}

运行结果如下说明反射已经破坏了单例模式.
在这里插入图片描述

反射破坏单例模式解决方案:

解决思路:通过反射去获取私有的构造方法,然后通过私有的构造方法创建对象.构造方法里面如果第一次调用,允许创建对象,然后要判断instance这个成员变量是否为空,如果不存在,允许创建对象,如果存在即抛出异常.

单例模式代码:
public class Singleton1 {
private static boolean flag = false;

//私有构造方法
private Singleton1(){
    //如果多线程的话,可能出现线程安全问题,所以要加上同步代码块.
    synchronized (Singleton1.class){

    //判断flag的值是否是true,如果是true,说明非第一次访问,直接抛一个异常,如果是false,说明第一次访问(即第一次调用构造方法创建对象)
    if(flag){
        throw new RuntimeException("不能创建多个对象!");
    }
    //将flag的值设置为true
    flag = true;
    }
}
//定义一个静态内部类
private static class SingletonHolder{
    //在内部类中声明并初始化外部类的对象
    private static final Singleton1 INSTANCE = new Singleton1();
}
//提供公共的访问方式
public static Singleton1 getInstance(){
    return Singleton1.SingletonHolder.INSTANCE;
}

//当进行反序列化时,会自动调用该方法,将该方法的返回值直接返回
public Object readResolve(){
    return Singleton1.SingletonHolder.INSTANCE;
}

}

测试类代码:
import java.lang.reflect.Constructor;

public class Client1 {
public static void main(String[] args) throws Exception{
//1,获取Singleton的字节码对象
Class clazz = Singleton1.class;
//2,获取无参构造方法对象
Constructor constructor = clazz.getDeclaredConstructor();
//3,取消访问检查
constructor.setAccessible(true);
//4,创建Singleton对象
Singleton1 singleton1 = (Singleton1) constructor.newInstance();
Singleton1 singleton2 = (Singleton1) constructor.newInstance();

    System.out.println(singleton1==singleton2);//如果返回true,没有破坏单例模式,如果返回false,破坏单例模式.

}

}
运行结果如下:
在这里插入图片描述
这里我们要看看是第一次调用无参构造方法创建对象出错,还是第二次出错.
我们在私有构造方法弄个断点,然后debug测试一下:
在这里插入图片描述
在这里插入图片描述

可以看到这里flag是flase,所以没有进入if判断语句,所以flag将会执行下一个语句,即flag=true,创建对象成功
在这里插入图片描述

当第二次调用无参构造方法创建对象时,因为flag=true,所以执行这段代码,抛出异常,成功解决了反射破坏单例模式.运行结果如下所示:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值