一、如何破环单例模式
破环单例模式很简单,使单例类创建多个对象即可,枚举方式除外
二、破坏单例模式的方式
常见的破环单例模式的方式就是序列化反序列化和反射
示例在:单例模式详解_crazyK.的博客-CSDN博客
1.序列化反序列化
以静态内部类创建单例模式为例
public class DestroySingleton {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//writeObjectFile();
readObjectFile();
//两次获取到的不是同一个对象,说明单例创建了多个对象,单例模式破坏成功
readObjectFile();
}
//向文件中写数据(对象)
public static void readObjectFile() throws IOException, ClassNotFoundException {
//创建对象输入流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\apple\\Desktop\\a.txt"));
//读取对象
LazyMan4 instance = (LazyMan4) ois.readObject();
System.out.println(instance);
//释放资源
ois.close();
}
//从文件中读数据(对象)
public static void writeObjectFile() throws IOException {
//获取单例对象
LazyMan4 instance = LazyMan4.getInstance();
//创建对象输出流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\apple\\Desktop\\a.txt"));
//写对象
oos.writeObject(instance);
//释放资源
oos.close();
}
}
writeObjectFile()方法会将对象创建出一个.txt文件,在调用readObjectFile()方法读取文件对象时,可以看到两个对象不相同,说明单例模式已被破坏
?
2.反射
以静态内部类创建的单例为例
public class DestroySingleton2 {
public static void main(String[] args) throws Exception {
//获取单例类的字节码对象
Class clazz = LazyMan4.class;
//获取无参构造方法对象
Constructor cons =clazz.getDeclaredConstructor();
//暴力反射
cons.setAccessible(true);
//创建对象
LazyMan4 l1 =(LazyMan4) cons.newInstance();
LazyMan4 l2 =(LazyMan4) cons.newInstance();
//false 两个对象地址不同,说明单例创建了对各对象,单例模式破坏成功
System.out.println(l1 == l2);
}
}
?
三、解决方案?
1.序列化反序列化
在单例类中添加readResolve()方法,在反序列化时被反射调用,如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回新new出来的对象
public class LazyMan implements Serializable {
private LazyMan(){}
//定义一个静态内部类
private static class LazyManHolder{
private static final LazyMan INSYANCE = new LazyMan();
}
//对外访问方法
public static LazyMan getInstance(){
return LazyMan.LazyManHolder.INSYANCE;
}
//防止被破坏
//当进行反序列化时,会自动调用该方法,将该方法的返回值直接反回
public Object readResolve(){
return LazyManHolder.INSYANCE;
}
}
?2.反射
在构造方法中加同步块
class LazyMan3{
private static boolean flag = false;
private LazyMan3() {
synchronized (LazyMan3.class) {
//判断flag的值是否为true,如果是true,说明非第一次访问,直接抛出一个异常
//如果为false,说明是第一次访问
if (flag) {
throw new RuntimeException("不能创建多个对象");
}//将flag设置为true
flag = true;
}
}
//定义一个静态内部类
private static class LazyMan3Holder{
private static final LazyMan3 INSYANCE = new LazyMan3();
}
//对外访问方法
public static LazyMan3 getInstance(){
return LazyMan3.LazyMan3Holder.INSYANCE;
}
}
?
|