懒汉式单例模式:
/**
* 测试饿汉式单例模式
* Created by GQ on 2019/4/17.
*/
public class Demo02 implements Serializable{
//类初始化时,不初始化这个对象(延时加载,真正使用的时候在创建)
private static Demo02 demo02;
private Demo02() {
if(demo02 != null){ // 防止反射调用构造器的漏洞
throw new RuntimeException();
}
}
//真正使用的时候才创建对象,资源利用率高
//使用同步方法,并发效率较低
public static synchronized Demo02 getInstance() {
if (demo02 == null) {
demo02 = new Demo02();
}
return demo02;
}
//反序列化时,如果定义了readResolve()方法,则直接返回此方法指定的对象,而不需要单独再创建新对象
private Object readResolve() throws ObjectStreamException{
return demo02;
}
}
测试:
/**
* 测试懒汉式单例模式(如何防止反射和反序列化漏洞)
* Created by GQ on 2019/4/17.
*/
public class Client2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException {
Demo02 d1 = Demo02.getInstance();
Demo02 d2 = Demo02.getInstance();
System.out.println(d1);
System.out.println(d2);
//反射漏洞(通过反射的方式直接调用私有构造器),解决方法:通过在自定义构造器中抛出异常处理
// Class<?> c = Class.forName("com.gq.study.pattern.singleton.Demo02");
// Constructor<Demo02> constructor = (Constructor <Demo02>) c.getDeclaredConstructor(null);
// constructor.setAccessible(true); // 跳过安全检查,访问私有方法
// Demo02 d3 = constructor.newInstance();
// Demo02 d4 = constructor.newInstance();
// System.out.println(d3);
// System.out.println(d4);
//反序列化漏洞(通过反序列化的方式构造多个对象),解决方法:在类中定义readResolve()方法,直接返回此方法指定的对象
FileOutputStream fos = new FileOutputStream("E:/Idea-git/MyStudy-Java/a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(d1);
oos.close();
fos.close();
FileInputStream fis = new FileInputStream("E:/Idea-git/MyStudy-Java/a.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
Demo02 d5 = (Demo02) ois.readObject();
System.out.println(d5);
}
}