Boolean.valueOf() 有时会生成 NullPointerException

2022-08-31 09:17:54

我有这个代码:

package tests;

import java.util.Hashtable;

public class Tests {

    public static void main(String[] args) {

        Hashtable<String, Boolean> modifiedItems = new Hashtable<String, Boolean>();

        System.out.println("TEST 1");
        System.out.println(modifiedItems.get("item1")); // Prints null
        System.out.println("TEST 2");
        System.out.println(modifiedItems.get("item1") == null); // Prints true
        System.out.println("TEST 3");
        System.out.println(Boolean.valueOf(null)); // Prints false
        System.out.println("TEST 4");
        System.out.println(Boolean.valueOf(modifiedItems.get("item1"))); // Produces NullPointerException
        System.out.println("FINISHED!"); // Never executed
    }
}

我的问题是,我不明白为什么测试3工作正常(它打印但不产生),而测试4抛出一个.正如您在测试 12 中看到的,并且等于 和 。falseNullPointerExceptionNullPointerExceptionnullmodifiedItems.get("item1")null

Java 7 和 8 中的行为是相同的。


答案 1

您必须仔细查看正在调用的重载:

  • Boolean.valueOf(null)正在调用 Boolean.valueOf(String)。这不会引发即使提供 null 参数。NPE
  • Boolean.valueOf(modifiedItems.get("item1"))正在调用 Boolean.valueOf(boolean),因为 的值的类型为 ,这需要取消装箱转换。因为 是 ,那么是该值的解装盒 - 而不是 - 会抛出NPE。modifiedItemsBooleanmodifiedItems.get("item1")nullBoolean.valueOf(...)

确定调用哪个重载的规则非常毛茸茸的,但它们大致如下:

  • 在第一遍中,将搜索方法匹配项,而不允许装箱/取消装箱(也不允许使用可变 arity 方法)。

    • 因为 是 可接受的值,但不是 ,在此传递中与 匹配;nullStringbooleanBoolean.valueOf(null)Boolean.valueOf(String)
    • Boolean对于 或 都不可接受,因此 在此传递中没有方法匹配。Boolean.valueOf(String)Boolean.valueOf(boolean)Boolean.valueOf(modifiedItems.get("item1"))
  • 在第二次传递中,将搜索方法匹配项,允许装箱/取消装箱(但仍然不是可变 arity 方法)。

    • A 可以取消装箱到 ,因此在此传递中匹配;但是编译器必须插入取消装箱转换才能调用它:BooleanbooleanBoolean.valueOf(boolean)Boolean.valueOf(modifiedItems.get("item1"))Boolean.valueOf(modifiedItems.get("item1").booleanValue())
  • (第三个传递允许可变 arity 方法,但在这里不相关,因为前两个传递与这些情况匹配)


答案 2

由于返回 a(不可强制转换为 a),因此将使用的签名是 Boolean.valueOf(布尔值),其中一旦返回到该处,则发件箱失败,并带有 .modifiedItems.getBooleanStringBooleanbooleannullNullPointerException