Java的单例模式,其实破解起来很方便,一旦破解单例就会失效,变成复例模式,一般有两种方式破解。
第一:反射方式破解,这种方式通过反射获取类,然后调用该类的构造函数创建对象,所以我们只需要在构造函数上做限制就好。把绿色部分的注释去掉,就可以防止单例破解了。
public class Singleton {
private static Singleton instance;
private Singleton() {
//if(instance != null) {throw new RuntimeException("救命啊,有坏蛋想破我");}
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
开始破解
public static void main(String[] args) throws Exception {
//反射获取单例类
Class<Singleton> claz = (Class<Singleton>) Class.forName("Singleton");
//通过反射获得原本私有的无参构造器
Constructor<Singleton> c = claz.getDeclaredConstructor(null);
//关闭安全检查
c.setAccessible(true);
//通过构造器实例化对象
Singleton s3 = c.newInstance();
Singleton s4 = c.newInstance();
System.out.println(s3);
System.out.println(s4);
}
运行结果:
singleton.Singleton@6d06d69c
singleton.Singleton@7852e922
方式二:序列化方式,这种方式问题主要是发生在反序列化的环节,每次反序列化都会生成新的对象,如果我们再生成新的对象时候让他返回老的对象就可以防止了,readResolve方法做控制就好
public class Singleton implements Serializable {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
//private Object readResolve(){
//return instance;
//}
}
开始破解:
public static void main(String[] args) throws Exception {
Singleton s1 = Singleton.getInstance();
System.out.println(s1);
//先序列化
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(s1);
//反序列化
InputStream is = new ByteArrayInputStream(os.toByteArray());
ObjectInputStream ois = new ObjectInputStream(is);
Singleton s2 = (Singleton) ois.readObject();
System.out.println(s2);
}