版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dingjianmin/article/details/79948677
被破坏的单例模式
我们知道饿汉单例天生是线程安全的,但是通过其他途径单例模式是可以被破坏的。懒汉亦如此。
1、通过反射来破解单例模式
public class Eagersingleton implements Serializable {
private static final long serialVersionUID = 888L;
private static Eagersingleton m_instance = new Eagersingleton();// 初始化时已经自行实例化
// 私有默认构造方法
private Eagersingleton() {
}
// 静态工厂方法
public static Eagersingleton getInstance() {
return m_instance;
}
}
public class Test1 {
public static void main(String[] args) throws NoSuchMethodException,
SecurityException {
// 获取单例对象
Eagersingleton instance = Eagersingleton.getInstance();
Eagersingleton instance2 = null;
try {
Class cls = Eagersingleton.class;
Constructor constructor = cls.getDeclaredConstructor(null);
// 关掉安全检查,可以调用私有构造器
constructor.setAccessible(true);
// 通过反射得到一个对象
instance2 = (Eagersingleton) constructor.newInstance(null);
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(instance);
System.out.println(instance2);
}
}
打印出来的结果不一样,说明这两个对象就是不同的对象,这样就破解了单例模式。
解决方案:避免反射
2、通过序列化和反序列化破解单例
public class Test2 {
public static void main(String[] args) throws FileNotFoundException,
ClassNotFoundException {
// 获取单例对象
Eagersingleton instance = Eagersingleton.getInstance();
// 通过反序列化读取对象
Eagersingleton instance2 = null;
try {
ObjectOutputStream oossStream = new ObjectOutputStream(
new FileOutputStream("D:/EagersingletonTest.txt"));
// 通过序列化把对象写到文件中
oossStream.writeObject(instance);
oossStream.flush();
oossStream.close();
// 读取文件的对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
"D:/EagersingletonTest.txt"));
instance2 = (Eagersingleton) ois.readObject();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(instance);
System.out.println(instance2);
}
}
打印出来的结果不一样,说明这两个对象就是不同的对象,破解了单例模式。
解决方案:避免序列化readResolve()这个方法是基于回调的,反序列化时,如果定义了readResolve()则直接返回此方法指定的对象,而不需要在创建新的对象。
每天努力一点,每天都在进步。