五种单例模式的安全性问题

来源:互联网 发布:unity3d在线编辑器 编辑:程序博客网 时间:2024/04/30 14:27

在之前两讲中,介绍了懒汉式、饿汉式、双重锁、内部类、枚举5种单例模式,其实单例模式还有很多种设计,在此就不一一介绍了。

在这5种单例模式中,枚举最为特殊,由于是官方提供的一种模式,所以不能被破解,是十分安全的。

在剩余4种中,我们以懒汉式为例说说安全问题。

正常调用代码:

public class Client {public static void main(String[] args) {Husband01 s011 = Husband01.getWife();Husband01 s012 = Husband01.getWife();System.out.println(s011);System.out.println(s012);System.out.println(s011 == s012);}}

输出结果
Husband01@c3c749Husband01@c3c749true

接下来,用反射破解单例模式:

import java.lang.reflect.Constructor;public class Client {public static void main(String[] args) throws Exception {Husband01 s011 = Husband01.getWife();Husband01 s012 = Husband01.getWife();//利用反射创建新对象Class<Husband01> h1 = (Class<Husband01>) Class.forName("Husband01");//反射获取H1对象Constructor c = h1.getDeclaredConstructor(null);//获取无参构造函数c.setAccessible(true);//更改无参构造函数权限为公开Husband01 s013 = (Husband01) c.newInstance(null);//创建新对象System.out.println(s011);System.out.println(s012);System.out.println(s013);System.out.println(s011 == s012);System.out.println(s011 == s013);}}
输出结果

Husband01@1bc4459Husband01@1bc4459Husband01@12b6651truefalse
另一种,利用反序列化破解(需实现Serializable)单例模式:

import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;public class Client {public static void main(String[] args) throws Exception {Husband01 s011 = Husband01.getWife();Husband01 s012 = Husband01.getWife();//利用反序列化创建新对象FileOutputStream fos = new FileOutputStream("d:/a.txt");ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(s011);fos.close();oos.close();FileInputStream fis = new FileInputStream("d:/a.txt");ObjectInputStream ois = new ObjectInputStream(fis);Husband01 s013 = (Husband01) ois.readObject();fis.close();ois.close();System.out.println(s011);System.out.println(s012);System.out.println(s013);System.out.println(s011 == s012);System.out.println(s011 == s013);}}
输出结果

Husband01@13bad12Husband01@13bad12Husband01@1a626ftruefalse
我们现在知道了如果破解,那么如果避免呢?

代码应该这样写!

import java.io.ObjectStreamException;import java.io.Serializable;/** * 懒汉式模式:在类加载时不初始化,当需要时再反馈(延迟加载) */public class Husband01 implements Serializable{//这句话看起来很奇怪,就理解为一开始每个男人都是没有老婆的private static Husband01 wife = null;//私有化老公,让小三无法拥有private Husband01(){if(wife != null){//防止反射破解throw new RuntimeException();}}//当家里人找你要老婆的时候public static synchronized Husband01 getWife(){//添加synchronized防止小三插入问题if(wife == null){wife = new Husband01();//这句话理解成老公和老婆结婚啦!}return wife;}// 防止反序列化破解    private Object readResolve() throws ObjectStreamException {            return wife;      } }
这样子,我们就能避免被破解啦?那么五种设计模式的效率如何呢?请看5种单例模式的效率问题!





0 0
原创粉丝点击