杰瑞科技汇

Java中null与null为何不等?

在 Java 中,null 关键字本身代表“无”或“空引用”,但两个 null 值的比较、方法调用、属性访问等操作,其结果和你直观的“等于”概念不完全一样。

Java中null与null为何不等?-图1
(图片来源网络,侵删)

下面我们从几个关键场景来深入理解。


使用 比较(最常见的情况)

这是最容易产生误解的地方。

比较的是两个引用变量是否指向内存中的同一个对象(同一个地址)。

  • 当两个变量都被赋值为 null 时: 它们都指向 JVM 中一个特殊的“空地址”,它们指向的是同一个“无”的概念,在这种情况下, 的判断结果是 true

    Java中null与null为何不等?-图2
    (图片来源网络,侵删)
    String a = null;
    String b = null;
    System.out.println(a == b); // 输出 true

    在这种情况下,null 等于 null

  • 当一个变量为 null,另一个变量指向一个实际创建的对象时: null 指向空地址,而另一个变量指向堆内存中某个对象的地址,地址不同, 的判断结果是 false

    String a = null;
    String b = new String("hello");
    System.out.println(a == b); // 输出 false

    在这种情况下,null 不等于 一个非 null 的对象。

小结: 使用 比较两个 null 值,结果是 truenull 不等于 null”这个说法在 比较下是错误的。

Java中null与null为何不等?-图3
(图片来源网络,侵删)

使用 equals() 方法比较

equals() 方法通常用于比较对象的内容(值)是否相等,而不是内存地址。

  • 当调用一个 null 对象的 equals() 方法时: 这会直接导致 NullPointerException (空指针异常),因为你试图通过一个“空引用”去访问一个方法。

    String a = null;
    String b = "hello";
    // 错误的做法!会抛出异常
    // System.out.println(a.equals(b)); 
    // 正确的做法(推荐)
    System.out.println(Objects.equals(a, b)); // 输出 false

    Objects.equals() 方法内部做了安全的 null 检查,它的工作原理是:

    1. anull,直接返回 false(因为 null 不可能等于一个非 null 的对象)。
    2. a 不是 null,再调用 a.equals(b)
  • 当两个变量都是 null 时: 同样,直接调用 a.equals(b) 会抛出异常。 但使用 Objects.equals(null, null),其结果是 true,因为 Objects 类的 equals 方法认为两个 null 值是相等的。

    String a = null;
    String b = null;
    // 错误的做法!会抛出异常
    // System.out.println(a.equals(b)); 
    // 正确的做法
    System.out.println(Objects.equals(a, b)); // 输出 true

小结:

  • 直接对 null 调用 equals() 会抛出异常,这是“null 不等于 null”这个说法的一个有力佐证(因为操作本身就不合法)。
  • 使用工具类(如 Objects.equals())可以安全地比较,并且认为 null 等于 null

switch 语句中的 null

在 Java 7 及更高版本中,switch 语句可以接受 String 类型,但它不能接受 null

  • switch 的表达式计算结果为 null,程序会抛出 NullPointerException

    String status = null;
    switch (status) {
        case "OPEN":
            System.out.println("状态是开启");
            break;
        case "CLOSED":
            System.out.println("状态是关闭");
            break;
        default:
            System.out.println("未知状态");
    }
    // 这段代码会抛出 NullPointerException

switch 语句中,null 是一个非法的输入,它会中断程序,这体现了 null 的“不等于”特性,因为它不能被当作一个有效的 case 值来处理。


instanceof 操作符

instanceof 用于检查一个对象是否是某个特定类或其子类的实例。

  • 当用 instanceof 检查 null 时: 结果永远是 false,因为 null 不代表任何类的实例。

    Object obj = null;
    System.out.println(obj instanceof String); // 输出 false
    System.out.println(null instanceof Object); // 输出 false

null 不 instance of 任何类型,这也是“null 不等于 null”思想的一种延伸——null 不是一个“东西”,所以它不属于任何类别。


操作 null 的行为 解释 "null 不等于 null" 是否适用?
a == b (当 a=null, b=null) true 两个引用都指向同一个“空地址”。 不适用null 等于 null
a.equals(b) (当 a=null) NullPointerException 尝试通过空引用访问方法,非法操作。 适用,操作本身无效,体现了“不等于”的特性。
Objects.equals(a, b) (当 a=null, b=null) true 工具类方法,安全地将两个 null 视为相等。 不适用null 等于 null
switch (a) (当 a=null) NullPointerException switch 语句不接受 null 作为有效输入。 适用null 不能被当作一个有效的 case 值。
a instanceof SomeClass (当 a=null) false null 不代表任何类的实例。 适用null 不属于任何类型。

核心思想

“Java null 不等于 null” 这句话更像是一种编程哲学或警示,而不是一个严格的语法规则,它的真正含义是:

null 是一个特殊的、表示“无”的值,它不是一个普通的对象,你不能用对待普通对象的方式来对待它。

  • 不要假设它有行为:不要对 null 调用方法或访问属性,否则会得到 NullPointerException
  • 不要假设它有类型instanceof 会告诉你它不属于任何类型。
  • 在比较时要多加小心:优先使用 Objects.equals()String.equals(Object) 这样的安全方式,而不是直接对 null 调用方法。

理解了 null 的这种“虚无”特性,就能写出更健壮、更不容易出错的 Java 代码。

分享:
扫描分享到社交APP
上一篇
下一篇