想要破坏单例模式,可以在定义的单例类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,所以执行这段代码,抛出异常,成功解决了反射破坏单例模式.运行结果如下所示: