You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单例与工厂模式下空指针异常原因排查求助

分析与解决:Singleton构造函数触发的空指针异常

我来帮你拆解这个棘手的问题——你遇到的空指针异常,根源在于类初始化阶段的循环依赖,以及静态变量的赋值时机。咱们一步步梳理整个执行流程,你就能明白为啥会出现null了:

问题触发的完整流程

  1. 当Main类调用Singleton.getInstance()时,Singleton类还未被初始化,JVM开始初始化它:
    • JVM先为Singleton的静态变量INSTANCE分配内存,默认值为null。
    • 接着执行INSTANCE = new Singleton():先创建Singleton实例(分配内存,实例变量value默认null),然后调用构造函数。
  2. Singleton构造函数执行:
    • 先调用configureSingleton(),把当前实例的value设为"TEST"(注意:此时只是当前实例的value有值,但静态变量INSTANCE仍然是null,因为new Singleton()的返回值还没赋值给INSTANCE!)
    • 然后调用Factory.build(),触发Factory类的初始化。
  3. Factory类初始化时执行静态块:
    • 调用Singleton.getInstance(),此时Singleton的静态变量INSTANCE还没被赋值(因为Singleton的构造函数还没执行完,INSTANCE = new Singleton()的赋值步骤还没完成),所以返回null。
    • 接着调用instance.getValue(),自然就抛出NullPointerException了!

解决方案

针对这个循环初始化的问题,有几个简单的修复方案,你可以根据场景选择:

方案1:把Factory静态块的逻辑移到build()方法内

静态块会在类初始化时自动执行,这正是问题的导火索。把逻辑移到build()方法里,就能确保只有当Singleton完全初始化后,才会执行这段代码:

public class Factory {
    private Factory() {
    }
    public static void build() {
        Singleton instance = Singleton.getInstance();
        System.out.println(instance.getValue());
        System.out.println("Building now");
    }
}

方案2:修改Singleton构造函数,移除对Factory.build()的调用

把Factory.build()的调用从Singleton构造函数中移到Main类或者其他合适的地方,避免在Singleton初始化过程中触发Factory的初始化:

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private String value;
    public static Singleton getInstance() {
        return INSTANCE;
    }
    private Singleton() {
        configureSingleton();
        // 移除这里的Factory.build()调用
    }
    // ... 其他方法不变
}

// Main类修改:
public class Main {
    public static void main(String[] args) {
        Singleton.getInstance().getValue();
        Factory.build();
    }
}

方案3:改用静态内部类实现单例(推荐)

这种方式能避免饿汉式单例在初始化阶段的循环依赖问题,因为静态内部类只会在第一次被访问时才会初始化:

public class Singleton {
    private String value;

    private Singleton() {
        configureSingleton();
        // 这里即使调用Factory.build()也不会有问题,因为INSTANCE已经初始化完成
    }

    // 静态内部类,只有当getInstance()被调用时才会加载
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private void configureSingleton() {
        value = "TEST";
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

内容的提问来源于stack exchange,提问作者Hauke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:24:22