首先我們還是拿餓漢模式作為栗子進行測試,餓漢模式的代碼如下:
public class HungrySingleton implements Serializable {
private static final HungrySingleton instance;
static {
instance = new HungrySingleton();
}
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return instance;
}
private Object readResolve(){
return instance;
}
1、先寫一個利用反射獲取實例的方法和直接獲取實例的方法,將兩者的返回值進行比較,看返回的是否是一個實例。
代碼如下:
public class Testreflection {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class object = HungrySingleton.class;
Constructor constructor = object.getDeclaredConstructor();
constructor.setAccessible(true);
HungrySingleton instance = HungrySingleton.getInstance();
HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance == newInstance);
}
}
運行后的結果為:可見,兩者的結果並不是一個對象,則餓漢模式毅然受到了反射的攻擊。

2、那么改如何解決這反射攻擊呢?我們知道是在類加載的時候就加載了這個實例的,因為是在類加載的時候就生成了詞實例,那么我們可以在構造器里面加一個判斷,進行反射防御。代碼如下:

測試結果為:

這種方式有一個特點,也就是它對類加載這個時刻就把對象創建好的這種類是ok的,靜態內部類的單例也可以用。
對於不是靜態類的也需要解決下,要根據創建實例的順序進行解決。但是無論如何反射都可以訪問到類的方法和變量,進行修改,所以非
類加載這個時刻就把對象創建好的這種類,是不能防止反射攻擊的。
