为什么 String.valueOf (null)抛出 NullPointerException?

根据文档,方法 String.valueOf(Object obj)返回:

如果参数是 null,则返回等于 "null"的字符串; 否则返回 obj.toString()的值。

但是为什么当我尝试这样做的时候:

System.out.println("String.valueOf(null) = " + String.valueOf(null));

它会抛出 NPE? (如果你不相信,自己试试!)

Exception in thread "main" java.lang.NullPointerException
at java.lang.String.(Unknown Source)
at java.lang.String.valueOf(Unknown Source)

为什么会这样? 文档是不是在骗我? 这是 Java 中的一个主要错误吗?

105733 次浏览

问题是 String.valueOf方法是 超载了:

Java 规约语言要求在这种情况下,选择 最具体的过载:

JLS 15.12.2.5选择最具体的方法

如果有多个成员方法既可访问又适用于方法调用,则有必要选择一个成员方法来为运行时方法分派提供描述符。Java 编程语言使用选择 非常具体方法的规则。

char[] 是安 Object但不是所有 Object 是 A char[]。因此,char[]具体点而不是 Object,而且正如 Java 语言所指定的那样,在本例中选择了 String.valueOf(char[])重载。

String.valueOf(char[])期望数组是非 null的,因为在这种情况下给出了 null,所以它抛出 NullPointerException

简单的“修正”是将 null明确地转换为 Object,如下所示:

System.out.println(String.valueOf((Object) null));
// prints "null"

相关问题


故事的寓意

这里有几个重要的问题:

  • 有效的 Java 第2版,第41项: 明智地使用重载
    • 就因为你可以超负荷工作,并不意味着你每次都应该超负荷工作
    • 它们可能导致混淆(特别是如果这些方法做的事情大相径庭的话)
  • 使用好的 IDE,您可以在编译时检查选择了哪个重载
    • 使用 Eclipse,您可以将鼠标悬停在上面的表达式上,然后看到选择了 的确,即 valueOf(char[])重载!
  • 有时候,您希望显式强制转换 null(后面的示例)

参见


关于选角 null

至少有两种情况需要显式地将 null强制转换为特定的引用类型:

  • 选择重载(如上例所示)
  • null作为单个参数赋给 vararg 参数

后者的一个简单例子如下:

static void vararg(Object... os) {
System.out.println(os.length);
}

然后,我们可以有以下:

vararg(null, null, null); // prints "3"
vararg(null, null);       // prints "2"
vararg(null);             // throws NullPointerException!


vararg((Object) null);    // prints "1"

参见

相关问题

问题是您正在调用 String.valueOf(char[])没有 String.valueOf(Object)

原因是 Java 总是选择使用提供的参数的重载方法的最特定版本。nullObject参数的有效值,但也是 char[]参数的有效值。

要让 Java 使用 Object版本,可以通过变量传入 null,或者指定对 Object 的显式强制转换:

Object o = null;
System.out.println("String.valueOf(null) = " + String.valueOf(o));
// or
System.out.println("String.valueOf(null) = " + String.valueOf((Object) null));

一个错误,编号 4867608是在2003年提出这种方式,这是解决了“不会修复”与这种解释。

由于兼容性限制,我们不能改变这一点 公共静态 String valueOf (char data [])方法 调用时,并没有提及替换 空参数。

2003年5月23日

在 Scala 中使用 String.valueOf(null: Any),否则将推断出 String.valueOf(null: Array[Char])。同样,在 java 中,如果你对隐式转换不满意,你需要一个显式转换。在 IntelliJ 中,使用 valueOf 的 Ctrl + B 将使您得到 valueOf 的版本,您可以使用其中的许多版本。