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

Java对象传入方法置空后仍可调用方法不抛空指针的原因

问题复现代码
public class SetClassNullExperiment {

    public static void main(String[] args) {
        SetMeNull c1 = new SetMeNull();
        c1.setInputToNull(c1);
        System.out.println("Is c1 equal to null? " + Boolean.toString(c1 == null)); // 输出false
        c1.printHelloWorld();

        SetMeNull c2 = new SetMeNull();
        c2 = null;
        System.out.println("Is c2 equal to null? " + Boolean.toString(c2 == null)); // 输出true
        c2.printHelloWorld(); // 抛出NullPointerException
    }

}

class SetMeNull {

    /**
     * 尝试将传入的对象引用设为null
     */
    public void setInputToNull(SetMeNull c) {
        c = null;
    }

    public void printHelloWorld() {
        System.out.println("Hello World!");
    }

}
底层原理

两组操作逻辑并不等价,核心原因是Java所有参数传递均为值传递,不存在引用传递:

  • 调用c1.setInputToNull(c1)时,方法形参c拿到的是c1变量存储值的副本——也就是c1指向的堆内存对象地址的拷贝,和main方法中的原始变量c1是两个完全独立的变量,只是初始阶段存了同一个地址值,指向同一个对象。
  • 方法内执行c = null,只是把形参这个临时变量存储的地址值改成了null,切断了形参和原对象的关联,完全不会改动main方法栈帧中c1本身存储的值。c1依旧指向最开始创建的SetMeNull实例,因此调用实例方法可以正常执行,不会抛出空指针。
  • 直接执行c2 = null时,修改的是main方法栈帧中c2变量本身的存储值,把原本存的对象地址直接替换为null,此时c2不再指向任何有效的堆内存对象,调用实例方法必然触发空指针异常。

补充说明:很多开发者会误以为Java传递对象类型参数是引用传递,实际传递的是「对象引用的拷贝值」。如果通过形参持有的地址修改对象内部属性,修改会同步到外部(因为两个变量指向同一个堆对象);但如果直接对形参本身重新赋值(设为null、指向新创建的对象),永远不会影响方法外的原始变量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 07:45:40