防止利用暴力反射破壞單例模式
阿新 • • 發佈:2021-01-12
單例模式的實現是將構造私有化,然後內部維護一個物件,但是還是可以通過暴力反射建立多個例項,程式碼如下:
我以上篇文章講的靜態內部類方式實現單例模式為例:
程式碼:
package com.hy.practice;
import sun.security.jca.GetInstance;
/**
* @author HY
* @ClassName UserService
* @Description 靜態內部類
* @DateTime 2020/12/27 10:45
* Version 1.0
*/
public class UserService {
//構造私有化
private UserService() {
}
private static class InnerClass {
//內部類內例項化
static UserService userService=new UserService();
}
public static UserService getInstance(){
return InnerClass.userService;
}
}
暴力反射建立多個物件:
Class<?> aClass = Class.forName("com.hy.practice.UserService");
Constructor<?> constructor = aClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object o1 = constructor.newInstance();
Object o2 = constructor.newInstance();
System. out.println(o1);
System.out.println(o2);
輸出:
可以看到,通過暴力反射可以呼叫私有的構造方法進行多次例項化,解決辦法就是在私有構造方法裡面判斷一下物件是否有例項。
程式碼:
package com.hy.practice;
import sun.security.jca.GetInstance;
/**
* @author HY
* @ClassName UserService
* @Description 靜態內部類
* @DateTime 2020/12/27 10:45
* Version 1.0
*/
public class UserService {
private static UserService instance;
//構造私有化
private UserService() {
if (instance!=null){
//說明有例項,直接報錯
throw new RuntimeException("對暴力反射說NO");
}
//沒有就讓他用一次
getInstance();
}
private static class InnerClass {
//內部類內例項化
private static UserService userService=new UserService();
}
public static UserService getInstance(){
return instance=InnerClass.userService;
}
}
測試程式碼:
Class<?> aClass = Class.forName("com.hy.practice.UserService");
Constructor<?> constructor = aClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object o1 = constructor.newInstance();
System.out.println(o1);
Object o2 = constructor.newInstance();
System.out.println(o2);
輸出結果:
可以看到第一次呼叫沒有問題,第二次呼叫就報錯了,所以就解決了此問題