前两篇介绍了创建单例模式的五种方式,而其中有四种(除了枚举)可以通过反射和反序列化破解的。
通过反射,创建两个不同的对象
package com.cb.study01;
import java.lang.reflect.Constructor;
/*
* 测试反射和反序列化
*/
public class Client1 {
public static void main(String[] args) throws Exception {
SingletonDemo06 sd01 = SingletonDemo06.getInstance();
SingletonDemo06 sd02 = SingletonDemo06.getInstance();
System.out.println(sd01);
System.out.println(sd02);
Class<SingletonDemo06> clazz = (Class<SingletonDemo06>) Class.forName("com.cb.study01.SingletonDemo06");
Constructor<SingletonDemo06> c = clazz.getDeclaredConstructor(null);
//跳过私有的权限检查
c.setAccessible(true);
SingletonDemo06 sd03 = c.newInstance();
SingletonDemo06 sd04 = c.newInstance();
System.out.println(sd03);
System.out.println(sd04);
}
}
运行结果
防止反射创建不同的对象
package com.cb.study01;
/*
* 测试懒汉式单例模式(如何防止反射和反序列化漏洞)
*/
public class SingletonDemo06 {
//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
private static SingletonDemo06 instance;
//私有构造器
private SingletonDemo06(){
//直接抛出一个异常
if (instance !=null) {
throw new RuntimeException();
}
}
//方法同步,调用效率低
public synchronized static SingletonDemo06 getInstance(){
if (instance==null) {
instance = new SingletonDemo06();
}
return instance;
}
}
运行结果:
通过反射来创建不同的对象,直接抛出异常。
通过反序列化创建多个不同的对象
package com.cb.study01;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
/*
* 测试反射
*/
public class Client2 {
public static void main(String[] args) throws Exception {
SingletonDemo07 sd01 = SingletonDemo07.getInstance();
SingletonDemo07 sd02 = SingletonDemo07.getInstance();
System.out.println(sd01);
System.out.println(sd02);
//通过反序列的方式构造多个对象
FileOutputStream fos = new FileOutputStream("d:a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(sd01);
oos.close();
fos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:a.txt"));
SingletonDemo07 s3 = (SingletonDemo07)ois.readObject();
System.out.println(s3);
}
}
运行结果:
防止反序列方法 构造多个对象
package com.cb.study01;
import java.io.ObjectStreamException;
import java.io.Serializable;
/*
* 测试反序列化
*/
public class SingletonDemo07 implements Serializable{
//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
private static SingletonDemo07 instance;
//私有构造器
private SingletonDemo07(){
//直接抛出一个异常
if (instance !=null) {
throw new RuntimeException();
}
}
//方法同步,调用效率低
public synchronized static SingletonDemo07 getInstance(){
if (instance==null) {
instance = new SingletonDemo07();
}
return instance;
}
//反序列时,如果定义了readResolve()则直接返回此方法打指定的对象,而不需要单独再创建新 对象
private Object readResolve() throws ObjectStreamException{
return instance;
}
}
运行结果:反序列时,如果定义了readResolve()则直接返回此方法打指定的对象,而不需要单独再创建新 对象