* 反射和反序列化可以破解除了枚举之外的4种实现方式。
反射破解单例:
TestDcl dcl1 = TestDcl.getInstance();
TestDcl dcl2 = TestDcl.getInstance();
System.out.println(dcl1);
System.out.println(dcl2);
//反射破解单例 两个不一样
Class<TestDcl> c = (Class<TestDcl>) Class.forName("cn.oyh.thread.TestDcl");
Constructor<TestDcl> con =c.getDeclaredConstructor();
con.setAccessible(true);
TestDcl dcl3 = con.newInstance();
TestDcl dcl4 = con.newInstance();
System.out.println(dcl3);
System.out.println(dcl4);
上面的TestDcl在这里可以找到,执行:
cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@677327b6
cn.oyh.thread.TestDcl@14ae5a5
会发现后面两个反射创建的对象和上面两个都不相同,单例模式是对外只有一个对象。那么怎么破解呢?很简单:
//1.构造器私有化
private TestDcl(){
// 防止反射创建多个对象:多次调用抛出异常,创建不成功
if(instance !=null){
throw new RuntimeException();
}
}
在构造器这改下代码就行了,在执行,会抛出异常。
反序列化破解单例:
也就是把单例模式反序列化,那么需要实现Serializable接口:
public class TestDcl implements Serializable{
TestDcl dcl1 = TestDcl.getInstance();
TestDcl dcl2 = TestDcl.getInstance();
System.out.println(dcl1);
System.out.println(dcl2);
//通过反序列化构造多个对象破解单例:需要实现Serializable接口
FileOutputStream fos = new FileOutputStream("src/copy.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(dcl1);
oos.close();
fos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/copy.txt"));
TestDcl dcl3 = (TestDcl) ois.readObject();
System.out.println(dcl3);
执行:
cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@3b9a45b3
反序列化的和上面不同,不是一个对象,怎么破解?在TestDcl类里添加一段代码即可:
/*
破解反序列化创建多个对象:
在反序列化时,如果定义了readResovle(),那么就直接返回那个对象,
而不需要创建新的对象。
*/
private Object readResolve() throws ObjectStreamException{
return instance;
}
执行:
cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@1540e19d
cn.oyh.thread.TestDcl@1540e19d