为什么反射能够破坏单例模式
单例模式是将构造方法私有化,而通过反射可以访问私有属性、私有方法、私有构造方法。
单例模式的演示
/**
* @author Administrator
* @date 2022/09/12
*/
public class PersonSingle {
private static PersonSingle instance;
private PersonSingle() {
}
public static PersonSingle getInstance() {
if (instance == null) {
instance = new PersonSingle();
}
return instance;
}
}
测试:
/**
* 单例模式演示
*
* @author Administrator
* @date 2022/09/12
*/
public class ReflexDemo13 {
public static void main(String[] args) {
PersonSingle p1 = PersonSingle.getInstance();
System.out.println(p1);
PersonSingle p2 = PersonSingle.getInstance();
System.out.println(p2);
PersonSingle p3 = PersonSingle.getInstance();
System.out.println(p3);
}
}
结果输出:
com.example.entity.PersonSingle@1b6d3586
com.example.entity.PersonSingle@1b6d3586
com.example.entity.PersonSingle@1b6d3586
反射破坏单例演示
/**
* 反射破坏单例演示
*
* @author Administrator
* @date 2022/09/12
*/
public class ReflexDemo14 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
PersonSingle p1 = PersonSingle.getInstance();
System.out.println(p1);
PersonSingle p2 = PersonSingle.getInstance();
System.out.println(p2);
PersonSingle p3 = PersonSingle.getInstance();
System.out.println(p3);
System.out.println("==============================");
// 获取类对象
Class<PersonSingle> personSingleClass = PersonSingle.class;
Constructor<PersonSingle> declaredConstructor = personSingleClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
PersonSingle personSingle = declaredConstructor.newInstance();
System.out.println(personSingle);
}
}
结果输出:
com.example.entity.PersonSingle@1b6d3586
com.example.entity.PersonSingle@1b6d3586
com.example.entity.PersonSingle@1b6d3586
==============================
com.example.entity.PersonSingle@4554617c
如何防止反射破坏单例
在PersonSingle的私有构造方法中,添加如下逻辑判断:
private PersonSingle() {
if (instance != null) {
throw new RuntimeException("实例对象已经存在,不能再创建了...");
}
}
结果输出:
com.example.entity.PersonSingle@1b6d3586
com.example.entity.PersonSingle@1b6d3586
com.example.entity.PersonSingle@1b6d3586
==============================
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.example.demo.ReflexDemo14.main(ReflexDemo14.java:28)
Caused by: java.lang.RuntimeException: 实例对象已经存在,不能再创建了...
at com.example.entity.PersonSingle.<init>(PersonSingle.java:13)
... 5 more
学习方式建议
头脑中有对应的理论知识方案,自己再去解决问题就简单了。同时自己要善于去思考在实现单例模式时,可能会存在的漏洞等问题。