为啥 String.valueOf(null) 会抛出 NullPointerException?

Posted

技术标签:

【中文标题】为啥 String.valueOf(null) 会抛出 NullPointerException?【英文标题】:Why does String.valueOf(null) throw a NullPointerException?为什么 String.valueOf(null) 会抛出 NullPointerException? 【发布时间】:2011-03-09 02:15:19 【问题描述】:

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

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

但是当我尝试这样做时怎么会:

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

它会抛出 NPE 吗? (不信你自己试试!)

线程“主”java.lang.NullPointerException 中的异常 在 java.lang.String.(Unknown Source) 在 java.lang.String.valueOf(未知来源)

这是怎么回事?文件是在骗我吗?这是 Java 的主要错误吗?

【问题讨论】:

【参考方案1】:

问题在于String.valueOf 方法被重载

String.valueOf(Object) String.valueOf(char[])

Java 规范语言要求在这些情况下,选择最具体的重载

JLS 15.12.2.5 Choosing the Most Specific Method

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

一个char[] is-an Object,但不是所有Object is-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"

相关问题

How does polymorph ambiguity distinction work? Which overload will get selected for null in Java?

故事的寓意

有几个重要的:

Effective Java 2nd Edition,第 41 条:明智地使用重载 仅仅因为你可以超载,并不意味着你每次都应该这样做 它们可能会引起混淆(尤其是当方法做的事情完全不同时) 使用好的IDE,可以在编译时检查选择了哪个重载 在 Eclipse 中,您可以将鼠标悬停在上述表达式上并看到 确实valueOf(char[]) 重载已被选中! 有时您想显式转换null(示例如下)

另见

Polymorphism vs Overriding vs Overloading Method Overloading. Can you overuse it?

在铸造null

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

选择重载(如上例所示) 将null 作为单个参数提供给可变参数

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

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"

另见

Java Language Guide/varargs - 了解它是如何实现的

相关问题

Why null cast? Difference between double… and double[] in formal parameter type declaration

【讨论】:

另一个建议:当你重载一个方法并且一个参数可以在两个重载上调用时(例如null在这种情况下),确保两个重载对于那个值的行为是一样的! @Joachim:我刚看了这个项目,惊喜地发现这两种方法被明确讨论过! Bloch 更进一步,声称由于String.valueOf(Object)valueOf(char[]) 无论如何都做了完全不同的事情(不管null 与否),也许它们一开始就不应该是重载。 有一个问题...如果您有一个返回 Object 的方法,那么语句 return null; 将与 return (Object) null; 完全相同?【参考方案2】:

问题是你打电话给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));

【讨论】:

【参考方案3】:

早在 2003 年就以这种方式提交了一个编号为 4867608 的错误,该错误已通过此解释解决为“无法修复”。

由于兼容性限制,我们无法更改此设置。请注意,它是 最终的公共静态 String valueOf(char data[]) 方法 被调用并且它没有提到将“null”替换为 空参数。

@###.### 2003-05-23

【讨论】:

【参考方案4】:

在 Scala 中使用 String.valueOf(null: Any)

【讨论】:

以上是关于为啥 String.valueOf(null) 会抛出 NullPointerException?的主要内容,如果未能解决你的问题,请参考以下文章

为啥没有 String.valueOf(short a);

为啥字符串连接比 String.valueOf 将 Integer 转换为 String 更快?

String.valueOf 的坑

三种String的转换 String.valueOf String强转 toString使用区别

string.valueOf()

String.valueOf()和toString()方法