52

看看下面的例子:

class nul
{
  public static void main (String[] args)
  {
    System.out.println (String.valueOf((Object)null));
    System.out.println (String.valueOf(null));
  }
}

第一个println写入null但第二个抛出一个NullPointerException.

为什么只有第二行值得例外?null而这两个s有什么区别呢?Java中有真假null null

4

3 回答 3

56

第一次调用将调用该String.valueOf(Object)方法,因为您已明确类型转换nullObject引用。相反,第二个将调用重载String.valueOf(char[])方法,因为它char[]比参数更具体。Objectnull

此方法还有其他接受原始参数的重载版本,但它们不是参数的有效匹配项null

JLS §15.12.2

可能有不止一种这样的方法,在这种情况下选择最具体的一种。最具体方法的描述符(签名加返回类型)是在运行时用于执行方法分派的描述符。

如果方法可以通过子类型(§15.12.2.2)适用,通过方法调用转换(§15.12.2.3)适用,或者它是适用的可变参数方法(§15.12.2.4),则该方法是适用的。

[...]

如果在适用性测试的三个阶段之一中确定了几种适用方法,则选择最具体的一种,如第 15.12.2.5 节所述。

现在检查这两种方法的源代码:

// This won't throw NPE for `obj == null`
public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

// This will throw `NPE` for `data == null`
public static String valueOf(char data[]) {
    return new String(data);
}
于 2013-10-11T11:33:50.347 回答
16

Java中有很多重载String.valueOf方法。此外,在 Javanull中具有任何和所有类型,因此任何(不是原始的)都可以是null.

因此,当您调用时,(String.valueOf((Object)null)调用valueOfObjectas 显式null转换为的方法Object

在第二个示例中,您没有显式地将 the 强制null转换为任何特定类型,因此实际上您使用抛出 NPEvalueOf的 a 调用该方法。char[]

来自JLS §15.12.2

第二步在上一步中确定的类型中搜索成员方法。此步骤使用方法的名称和参数表达式的类型来定位可访问且适用的方法,即可以在给定参数上正确调用的声明。

可能有不止一种这样的方法,在这种情况下选择最具体的一种。最具体方法的描述符(签名加返回类型)是在运行时用于执行方法分派的描述符。

在这种情况下,它比没有显式转换时调用char[]更具体Objectnull

于 2013-10-11T11:39:47.910 回答
6

虽然我已经接受了一个答案,但我想为这个问题添加确切的答案,因为这两个答案集中在解释我走进的陷阱。

(Object)null和之间的区别在于null,第一个类型是强制的,Object而第二个的类型不是,正如人们想象的那样,是强制的Object。相反,它也可以是一个数组而不是一个对象。

所以结论是:传递(Object)null而不是null作为参数传递给方法,以确保准确地获得在对象上工作的方法,而不是在数组上工作的任何其他方法。

于 2013-10-11T14:28:36.383 回答