静态内部类能实现懒加载,因为jvm规范要求其在外部类加载时不初始化,仅首次调用getinstance()触发singletonholder类加载并执行创建instance,兼顾懒加载与线程安全。

为什么静态内部类能实现懒加载
因为 JVM 规范明确要求:静态内部类在外部类加载时不会被初始化,只有首次主动使用(比如调用 getInstance() 中引用到它)时,才会触发其 <clinit>()</clinit> 方法执行 —— 也就是真正创建 INSTANCE 的那一刻。这比饿汉式提前初始化更省资源,也比双重检查锁少一层同步开销。
私有构造方法必须写,且不能带参数
这是单例成立的底线。如果构造方法不是 private,外部代码就能直接 new Singleton() 破坏唯一性;如果带参数(比如 private Singleton(String name)),静态内部类里 new Singleton() 就会编译失败 —— 因为内部类无法访问外部类的非常量非静态成员,更没法传参。
- 构造方法体可以为空,但必须存在
- 不能是
protected或包级可见,否则子类或同包类可能绕过 - 不要在构造方法里做耗时操作(如网络请求、文件读取),否则首次调用
getInstance()会卡住主线程
静态内部类的命名和结构有硬性约束
内部类必须是 static,且只能包含一个 public static final 的实例字段,比如 INSTANCE。任何多余逻辑(如静态块、额外字段、非 final 实例)都会破坏“仅加载一次 + 唯一实例”的保证。
- 类名建议用
Holder或SingletonHolder,语义清晰 -
INSTANCE必须是static final,否则无法确保不可变性和线程安全 - 不能在内部类里调用外部类的非静态方法,也不该持有外部类引用
- 不要给内部类加任何访问修饰符(
public/private都非法),它默认就是包级私有
getInstance() 方法看似简单,但调用时机很关键
这个方法只是返回 Inner.INSTANCE,本身不加锁、不判空、不 volatile —— 它的线程安全性完全依赖 JVM 类加载机制的原子性。但这也意味着:一旦某个线程触发了内部类初始化,其他线程再进来就会直接拿到已构建好的实例,不会有竞态。
- 方法必须是
public static,否则外部无法调用 - 返回类型必须和外部类一致,不能是内部类类型
- 不要在
getInstance()里加日志、计数器等副作用逻辑,否则会影响类加载行为判断 - Android 上注意避免在 Application 初始化前就调用它,否则可能因类加载顺序引发 NoClassDefFoundError
final 字段就已经被赋值完成了。











