模擬反射攻擊
餓漢式模擬
餓漢式
public class HungrySingleton implements Serializable {
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton=new HungrySingleton();
}
private HungrySingleton(){
if(HungrySingleton.getInstance()!=null){
throw new RuntimeException("單例構造器禁止反射調用");
}
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
private Object readResolve(){
return hungrySingleton;
}
}
測試類
public class Test {
public static void main(String[] args) throws Exception {
Class objectClass=HungrySingleton.class;
Constructor constructor=objectClass.getDeclaredConstructor();
constructor.setAccessible(true);
HungrySingleton newInstance=HungrySingleton.getInstance();
HungrySingleton instance= (HungrySingleton) constructor.newInstance();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance==newInstance);
}
}
結果如圖:
原因在類加載時就完成初始化
懶漢式模擬
public class LazySingleton {
//聲明靜態的要被單例的對象
private static LazySingleton lazySingleton=null;
private static boolean flag=true;
//私有構造器,爲了不讓外部new
private LazySingleton(){
if(flag){
flag=false;
}else {
throw new RuntimeException("單例構造器禁止反射調用");
}
}
//加synchronized鎖了整個類
public synchronized static LazySingleton getInstance(){
if(lazySingleton==null){
lazySingleton=new LazySingleton();
}
return lazySingleton;
}
public static void main(String[] args) throws Exception {
Class objClass=LazySingleton.class;
Constructor constructor=objClass.getDeclaredConstructor();
constructor.setAccessible(true);
LazySingleton o1=LazySingleton.getInstance();
//反射攻擊,修改值
Field flag=o1.getClass().getDeclaredField("flag");
flag.setAccessible(true);
flag.set(o1,true);
LazySingleton o2= (LazySingleton) constructor.newInstance();
System.out.println(o1);
System.out.println(o2);
System.out.println(o1==o2);
}
}