对于在类加载时创建单例对象 1.静态内部类单例 2.饿汉式单例 在私有构造器内部加判断即可抵御反射攻击(下面以饿汉式单例为例)
public class HungarySingleton {
private static final HungarySingleton hungarySingleton;
static {
hungarySingleton = new HungarySingleton();
}
private HungarySingleton() {
//类初始化的时候已经创建了单例,反射可以通过调用私有的构造器创建单例实例,此处的判断防止反射调用
if (hungarySingleton != null) {
throw new RuntimeException("单例构造器防止反射调用");
}
}
public static HungarySingleton getInstance() {
return hungarySingleton;
}
}
测试
HungarySingleton instance = HungarySingleton.getInstance();
Constructor constructor = HungarySingleton.class.getDeclaredConstructor();
constructor.setAccessible(true);//对私有构造器开放权限
HungarySingleton newInstance = (HungarySingleton) constructor.newInstance();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(instance == newInstance);
3.懒汉式单例 通过设置标记抵御反射攻击 但是通过反射可以修改属性的值 结果依然失败
public class LazyDoubleCheckSingleton {
private volatile static LazyDoubleCheckSingleton lazySingleton = null;
private static Boolean flag = true;
private LazyDoubleCheckSingleton() {
if (flag){
flag = false;
} else {
throw new RuntimeException("懒汉式抵御反射攻击");
}
// if (lazySingleton != null) {
// throw new RuntimeException("懒汉式抵御反射攻击");
// }
}
public static LazyDoubleCheckSingleton getInstance() {
if (lazySingleton == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (lazySingleton == null) {
lazySingleton = new LazyDoubleCheckSingleton();
}
}
}
return lazySingleton;
}
}
测试
LazyDoubleCheckSingleton instance = LazyDoubleCheckSingleton.getInstance();
Field flag = LazyDoubleCheckSingleton.class.getDeclaredField("flag");
flag.setAccessible(true);
flag.set(instance, true);
Constructor constructor = LazyDoubleCheckSingleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
LazyDoubleCheckSingleton newInstance = (LazyDoubleCheckSingleton) constructor.newInstance();
System.out.println(instance);
System.out.println(newInstance);
System.out.println(newInstance == instance);