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

Java中MyThread初始化抛NullPointerException,为何s未被初始化?

问题原因分析与解决方案

这是个很典型的Java实例初始化顺序问题,我来给你理清楚为什么会抛出NullPointerException:

核心问题:Java对象的初始化顺序和你的预期相反

当你调用new MyThread("name")创建对象时,JVM的执行流程是这样的:

  1. 先为MyThread对象分配内存,所有实例变量会被默认初始化——也就是String s被设为null,char[] ch也被设为null。
  2. 接下来,JVM会按照实例变量在类中声明的顺序执行它们的初始化表达式。你的代码里char[] ch = s.toCharArray();(也就是你标注的第1行)写在构造器之前,所以这一步会先执行。但此时构造器里的this.s = s还没运行,s仍然是null,调用null.toCharArray()自然就触发空指针异常了。
  3. 只有当所有实例变量的初始化都完成后,JVM才会执行构造器里的代码(包括给s赋值和打印"Constructor")。

你误以为构造器会先给s赋值,之后才初始化ch,但实际顺序刚好相反——实例变量的初始化逻辑会先于构造器体的执行。

修复方案

有两种简单的方式可以解决这个问题:

方案1:把ch的初始化移到构造器中

这是最直观的方式,确保s已经被赋值后再初始化ch:

class MyThread implements Runnable {
    String s;
    char[] ch; // 仅声明,不提前初始化

    MyThread(String s) {
        this.s = s;
        this.ch = s.toCharArray(); // 此时s已经有值了
        System.out.println("Constructor");
    }

    public void run() {
        for (char c : ch) {
            System.out.println(c);
        }
    }
}

方案2:使用实例初始化块(适合多构造器复用场景)

如果你的类有多个构造器,不想重复写ch的初始化逻辑,可以用实例初始化块(不过还是建议配合构造器先给s赋值,避免空指针):

class MyThread implements Runnable {
    String s;
    char[] ch;

    MyThread(String s) {
        this.s = s;
        // 构造器内先赋值,再初始化ch
        this.ch = s.toCharArray();
        System.out.println("Constructor");
    }

    // 实例初始化块,会在构造器执行前运行,但这里依赖构造器先给s赋值
    {
        // 可以在这里统一处理ch的初始化逻辑,适合多构造器场景
        if (s != null) {
            ch = s.toCharArray();
        }
    }

    public void run() {
        for (char c : ch) {
            System.out.println(c);
        }
    }
}

总结

记住这个关键规则:类中声明的实例变量的初始化表达式,会在构造器体的代码执行之前运行。所以不要在实例变量的初始化逻辑中,依赖那些只有构造器才会赋值的变量,否则很容易踩空指针的坑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:18:13