Java中带名称的静态初始化器是否合法?解析Core Java示例编译报错
按需初始化代码编译失败的原因及修复
我只认识static {...}格式的静态初始化器,但在Cay Horstmann的《Core Java》12.4.13节「按需初始化」里,出现了private static Holder {...}的写法,目的是利用JVM仅在类首次使用时执行一次静态初始化的特性,实现单例的按需初始化且保证只初始化一次。但给出的代码编译报错,具体代码和错误信息如下:
原错误代码
public class OnDemandData { // private constructor to ensure only one object is constructed private OnDemandData() {} public static OnDemandData getInstance() { return Holder.INSTANCE; } // only initialized on first use, i.e. in the first call to getInstance private static Holder { // VM guarantees that this happens at most once static final OnDemandData INSTANCE = new OnDemandData(); } }
编译报错信息
/OnDemandData.java:12: error: <identifier> expected private static Holder { ^ /OnDemandData.java:14: error: illegal start of expression static final OnDemandData INSTANCE = new OnDemandData(); ^ /OnDemandData.java:17: error: class, interface, enum, or record expected } ^ 3 errors
问题根源
这是书中的笔误,原代码混淆了静态初始化块和静态内部类的语法规则:
- 第12行的
private static Holder {缺少类定义的关键字class,JVM无法识别这是一个类,因此报<identifier> expected错误 - 第14行在内部类的成员前多写了
static——因为Holder本身是静态内部类,其成员默认属于类级别,不需要重复添加static修饰符,这属于语法错误 - 最后一行多余的
}是前面类定义不完整导致的语法错位
修正后的正确代码
public class OnDemandData { // 私有构造方法,禁止外部实例化 private OnDemandData() {} public static OnDemandData getInstance() { return Holder.INSTANCE; } // 私有静态内部类,仅在首次访问时被JVM加载初始化 private static class Holder { // JVM保证静态成员的初始化线程安全且仅执行一次 static final OnDemandData INSTANCE = new OnDemandData(); } }
核心原理
这种写法是经典的按需初始化Holder模式:
- 静态内部类
Holder不会随外部类OnDemandData的加载而初始化,只有当调用getInstance()方法、访问Holder.INSTANCE时,Holder类才会被加载 - JVM的类加载机制天然保证了静态成员初始化的线程安全性,不需要额外加锁就能实现线程安全的懒加载单例
内容的提问来源于stack exchange,提问作者sevengold
相关产品推荐
相关产品推荐

