单例模式的实现是将构造私有化,然后内部维护一个对象,但是还是可以通过暴力反射创建多个实例,代码如下:
我以上篇文章讲的静态内部类方式实现单例模式为例:
代码:
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);
输出结果:
可以看到第一次调用没有问题,第二次调用就报错了,所以就解决了此问题