反射花式破坏单例

it2025-07-11  4

反射花式破坏单例

懒汉式

反射破坏单例代码演示: package singleton; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @author liouwb * 单例模式 * 懒汉式 */ public class SingletonLazyTest { public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { // 懒汉式 SingletonLazy lazy = SingletonLazy.getInstance(); SingletonLazy lazy1 = SingletonLazy.getInstance(); // 通过反射实例 Class<SingletonLazy> lazyClass = SingletonLazy.class; Constructor<SingletonLazy> constructor = lazyClass.getDeclaredConstructor(); constructor.setAccessible(true); SingletonLazy lazy2 = constructor.newInstance(); // 验证单例是否全局只有一个实例 System.out.println("正常获取的实例比较:" + (lazy == lazy1)); System.out.println("正常获取实例与反射获取比较:" + (lazy == lazy2)); // 输出对象信息 System.out.println("lazy :" + lazy); System.out.println("lazy1:" + lazy1); System.out.println("lazy2:" + lazy2); } /** * 懒汉式 */ static class SingletonLazy { // public static SingletonLazy instance; // 私有构造函数 private SingletonLazy() { } public static SingletonLazy getInstance() { if (instance == null) { instance = new SingletonLazy(); } return instance; } } } 反射破坏单例结果输出: 正常获取的实例比较:true 正常获取实例与反射获取比较:false lazy :singleton.SingletonLazyTest$SingletonLazy@4554617c lazy1:singleton.SingletonLazyTest$SingletonLazy@4554617c lazy2:singleton.SingletonLazyTest$SingletonLazy@74a14482 Process finished with exit code 0
结论:
从结果可以看出,lazy 和 lazy1是正常获取的,是同一实例lazy2通过反射获取的,与lazy 和 lazy1已经不是同一实例懒汉式的单例被反射破坏

饿汉式

代码演示: package singleton; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @author liouwb * 单例模式 * 饿汉式 */ public class SingletonHungryTest { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 饿汉式 SingletonHungry hungry = SingletonHungry.getInstance(); SingletonHungry hungry1 = SingletonHungry.getInstance(); // 通过反射实例 Class<SingletonHungry> hungryClass = SingletonHungry.class; Constructor<SingletonHungry> constructor = hungryClass.getDeclaredConstructor(); constructor.setAccessible(true); SingletonHungry hungry2 = constructor.newInstance(); // 验证单例是否全局只有一个实例 System.out.println("饿汉式正常获取的实例比较:" + (hungry == hungry1)); // 正常获取实例与反射获取实例对比 System.out.println("饿汉式正常获取的实例与反射获取实例比较:" + (hungry == hungry2)); // 输出对象信息 System.out.println("hungry :" + hungry); System.out.println("hungry1:" + hungry1); System.out.println("hungry2:" + hungry2); } /** * 饿汉式 */ static class SingletonHungry { private static SingletonHungry instance = new SingletonHungry(); /** * 构造函数 * * @return */ private SingletonHungry() { } /** * @return */ public static SingletonHungry getInstance() { return instance; } } } 输出结果: 饿汉式正常获取的实例比较:true 饿汉式正常获取的实例与反射获取实例比较:false hungry :singleton.SingletonHungryTest$SingletonHungry@4554617c hungry1:singleton.SingletonHungryTest$SingletonHungry@4554617c hungry2:singleton.SingletonHungryTest$SingletonHungry@74a14482 Process finished with exit code 0
结论:
从结果可以看出,hungry 和 hungry1 是正常获取的,是同一实例hungry2通过反射获取的,与hungry 和 hungry1 已经不是同一实例饿汉式的单例被反射破坏

检查锁单例模式

代码演示: package singleton; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @author liouwb * 单例模式 * 懒汉式 加锁(饿汉式加锁,效果一样): 线程安全,可以被反射破坏 */ public class SingletonLazyLockTest { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 懒汉式 加锁 SingletonLazyLock lazyLock = SingletonLazyLock.getInstance(); SingletonLazyLock lazyLock1 = SingletonLazyLock.getInstance(); // 通过反射实例 Class<SingletonLazyLock> lazyClass = SingletonLazyLock.class; Constructor<SingletonLazyLock> constructor = lazyClass.getDeclaredConstructor(); constructor.setAccessible(true); SingletonLazyLock lazyLock2 = constructor.newInstance(); // 验证单例是否全局只有一个实例 System.out.println("正常获取的实例比较:" + (lazyLock == lazyLock1)); // 反射获取与正常获取对比 System.out.println("正常获取的实例比较:" + (lazyLock == lazyLock2)); // 输出相应对象 System.out.println("lazyLock :" + lazyLock); System.out.println("lazyLock1:" + lazyLock1); System.out.println("lazyLock2:" + lazyLock2); } /** * 懒汉式 加锁 */ static class SingletonLazyLock { // public static SingletonLazyLock instance; // 私有构造函数 private SingletonLazyLock() { } public static synchronized SingletonLazyLock getInstance() { if (instance == null) { instance = new SingletonLazyLock(); }else { throw new RuntimeException("禁止使用反射破坏单例"); } return instance; } } } 结果输出: 正常获取的实例比较:true 正常获取的实例比较:false lazyLock :singleton.SingletonLazyLockTest$SingletonLazyLock@4554617c lazyLock1:singleton.SingletonLazyLockTest$SingletonLazyLock@4554617c lazyLock2:singleton.SingletonLazyLockTest$SingletonLazyLock@74a14482 Process finished with exit code 0
结论:
从结果可以看出,lazyLock和 lazyLock1是正常获取的,是同一实例lazyLock2通过反射获取的,与lazyLock和 lazyLock1已经不是同一实例加锁之后的单例看似很安全,但仍然可以被反射破坏

双重检查锁

代码演示: package singleton; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @author liouwb * 单例模式 双重检查锁 */ public class SingletonDoubleCheckLockTest { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 懒汉式 双重检查锁 SingletonLazyDoubleLock lazyDoubleLock = SingletonLazyDoubleLock.getInstance(); SingletonLazyDoubleLock lazyDoubleLock1 = SingletonLazyDoubleLock.getInstance(); // 通过反射实例 Class<SingletonLazyDoubleLock> lazyClass = SingletonLazyDoubleLock.class; Constructor<SingletonLazyDoubleLock> constructor = lazyClass.getDeclaredConstructor(); constructor.setAccessible(true); SingletonLazyDoubleLock lazyDoubleLock2 = constructor.newInstance(); // 验证单例是否全局只有一个实例 System.out.println("正常获取的实例比较:" + (lazyDoubleLock == lazyDoubleLock1)); // 反射获取与正常获取对比 System.out.println("正常获取的实例比较:" + (lazyDoubleLock == lazyDoubleLock2)); // 输出相应对象 System.out.println("lazyDoubleLock :" + lazyDoubleLock); System.out.println("lazyDoubleLock1:" + lazyDoubleLock1); System.out.println("lazyDoubleLock2:" + lazyDoubleLock2); } /** * 懒汉式 双重加锁 */ static class SingletonLazyDoubleLock { // public static SingletonLazyDoubleLock instance; // 私有构造函数 private SingletonLazyDoubleLock() { } public static synchronized SingletonLazyDoubleLock getInstance() { if (instance == null) { synchronized (SingletonLazyDoubleLock.class) { if (instance == null) { instance = new SingletonLazyDoubleLock(); } } } return instance; } } } 结果: 正常获取的实例比较:true 正常获取的实例比较:false lazyDoubleLock :singleton.SingletonDoubleCheckLockTest$SingletonLazyDoubleLock@4554617c lazyDoubleLock1:singleton.SingletonDoubleCheckLockTest$SingletonLazyDoubleLock@4554617c lazyDoubleLock2:singleton.SingletonDoubleCheckLockTest$SingletonLazyDoubleLock@74a14482 Process finished with exit code 0
结论:
从结果可以看出,lazyDoubleLock 和 lazyDoubleLock2是正常获取的,是同一实例lazyDoubleLock 通过反射获取的,与lazyDoubleLock 和 lazyDoubleLock2已经不是同一实例双重检查锁单例仍然可以被反射破坏

静态内部类

代码演示: package singleton; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @author liouwb * 单例模式 静态内部类 */ public class SingletonInnerTest { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 单例静态内部类 SingletonInner inner = SingletonInner.getInstance(); SingletonInner inner1 = SingletonInner.getInstance(); // 通过反射实例 Class<SingletonInner> lazyClass = SingletonInner.class; Constructor<SingletonInner> constructor = lazyClass.getDeclaredConstructor(); constructor.setAccessible(true); SingletonInner inner2 = constructor.newInstance(); // 验证单例是否全局只有一个实例 System.out.println("正常获取的实例比较:" + (inner == inner1)); // 反射获取与正常获取对比 System.out.println("正常获取的实例比较:" + (inner == inner2)); // 输出相应对象 System.out.println("inner :" + inner); System.out.println("inner1:" + inner1); System.out.println("inner2:" + inner2); } /** * 单例静态内部类 */ static class SingletonInner { private SingletonInner() { } private static class SingletonHoler { private static SingletonInner INSTANCE = new SingletonInner(); } public static final SingletonInner getInstance() { return SingletonHoler.INSTANCE; } } } 结果: 正常获取的实例比较:true 正常获取的实例比较:false inner :singleton.SingletonInnerTest$SingletonInner@4554617c inner1:singleton.SingletonInnerTest$SingletonInner@4554617c inner2:singleton.SingletonInnerTest$SingletonInner@74a14482 Process finished with exit code 0
结论:
被反射破坏

枚举单例

代码演示: package singleton; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @author liouwb * 单例模式 枚举 */ public class SingletonEnumTest { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { // 单例 枚举 SingletonEnum singletonEnum = SingletonEnum.getInstance(); SingletonEnum singletonEnum1 = SingletonEnum.getInstance(); // 通过反射实例 Class<SingletonEnum> singletonEnumClass = SingletonEnum.class; Constructor<SingletonEnum> constructor = singletonEnumClass.getDeclaredConstructor(); constructor.setAccessible(true); SingletonEnum singletonEnum2 = constructor.newInstance(); // 验证单例是否全局只有一个实例 System.out.println("正常获取的实例比较:" + (singletonEnum == singletonEnum1)); // 反射获取与正常获取对比 System.out.println("正常获取的实例比较:" + (singletonEnum == singletonEnum2)); // 输出相应对象 System.out.println("singletonEnum :" + singletonEnum.hashCode()); System.out.println("singletonEnum1:" + singletonEnum1.hashCode()); System.out.println("singletonEnum2:" + singletonEnum2.hashCode()); } /** * 枚举 单例 */ enum SingletonEnum { INSTANCE; public static SingletonEnum getInstance() { return INSTANCE; } } } 结果: Exception in thread "main" java.lang.NoSuchMethodException: singleton.SingletonEnumTest$SingletonEnum.<init>() at java.lang.Class.getConstructor0(Class.java:3074) at java.lang.Class.getDeclaredConstructor(Class.java:2170) at singleton.SingletonEnumTest.main(SingletonEnumTest.java:20) Process finished with exit code 1
结论:
通过反射获取枚举单例实例异常枚举形式的单例不能通过反射

防止反射破坏单例

通过上述示例可以看出枚举可以防止单例破坏反射可以获取到单例类的私有构造,然后实例化

通过修改私有构造可以防止反射破坏单例

方式一、私有构造函数加锁
// 私有构造函数 private SingletonLazyLock() { synchronized (SingletonLazyLock.class) { if (instance != null) { throw new RuntimeException("不要用反射破坏单例"); } } } 结果
方式二、私有构造函数加标识位
/** * 懒汉式 */ static class SingletonLazy { // public static SingletonLazy instance; private static boolean flag = false; // 私有构造函数 private SingletonLazy() { synchronized (SingletonLazy.class) { if (!flag) { flag = true; } else { throw new RuntimeException("不要用反射破坏单例"); } } } public static SingletonLazy getInstance() { if (instance == null) { instance = new SingletonLazy(); } return instance; } }

最新回复(0)