单例模式:静态初始化与枚举实现的初始化时机差异
静态初始化与枚举实现单例的实例创建时机差异分析
一、静态初始化单例的创建时机
静态初始化单例是标准的饿汉式(eager initialization),实例创建时机固定在JVM类加载的初始化阶段:
- 只要类被触发加载(比如调用类的静态方法、访问静态字段、通过
Class.forName()加载类等),就会立即初始化静态字段INSTANCE,完成实例创建。 - 即便后续全程没有调用
getInstance()获取实例,只要类被加载,实例就已经存在于内存中。
示例代码:
public class StaticSingleton { private static final StaticSingleton INSTANCE = new StaticSingleton(); private StaticSingleton() {} public static StaticSingleton getInstance() { return INSTANCE; } }
二、枚举实现单例的创建时机
枚举实现单例的实例创建时机依赖于枚举类的首次主动使用:
- 枚举类的实例是在枚举类被触发初始化时创建的,而初始化必须由主动操作触发,比如:访问枚举实例(
EnumSingleton.INSTANCE)、调用枚举的静态方法、通过反射获取枚举类的实例等。 - 如果只是被动加载枚举类(比如通过
Class.forName("com.example.EnumSingleton", false, classLoader)这种不触发初始化的方式),枚举实例不会被创建;只有当首次主动使用枚举类时,才会完成实例的初始化。
示例代码:
public enum EnumSingleton { INSTANCE; public void doSomething() {} }
三、两种实现的场景对比
1. 全程未使用实例的场景
- 静态初始化单例:只要类被加载(哪怕是被其他类间接依赖触发加载),实例就会被创建。
- 枚举单例:如果枚举类从未被主动使用,哪怕类被加载,实例也不会被创建,直到有主动操作触发枚举类的初始化。
2. 使用实例的场景
- 静态初始化单例:实例在类加载阶段就已创建,第一次调用
getInstance()只是返回已存在的实例。 - 枚举单例:第一次访问
INSTANCE时触发枚举类初始化,创建实例;后续访问直接返回已创建的实例。
四、枚举实现是否属于饿汉式?
严格来说,枚举实现不属于传统意义上的饿汉式:
- 传统饿汉式是类加载即初始化实例,而枚举是首次主动使用时才初始化实例,初始化时机更可控。
- 但由于枚举实例一旦触发初始化就会立即创建,且线程安全由JVM原生保证,部分资料也会将其归为饿汉式的变体——它不会像懒汉式那样延迟到获取实例的方法被调用才初始化,而是在枚举类首次被主动使用时就完成实例创建。
内容的提问来源于stack exchange,提问作者Devesh Kumar
相关产品推荐
相关产品推荐

