看看下面的例子:
class nul
{
public static void main (String[] args)
{
System.out.println (String.valueOf((Object)null));
System.out.println (String.valueOf(null));
}
}
第一个println
写null
,但第二个NullPointerException
。{/ p>
为什么只有第二行值得例外?这两个null
之间有什么区别? Java中是否有真正的 null
和假 null
?
答案 0 :(得分:56)
第一次调用将调用String.valueOf(Object)
方法,因为您明确地将null
标记为Object
引用。相反,第二个方法将调用重载的String.valueOf(char[])
方法,因为char[]
对于Object
参数比null
更具体。
此方法的其他重载版本接受原始参数,但这些参数不是null
参数的有效匹配。
来自JLS §15.12.2:
可能有多种这样的方法,在这种情况下最多 选择特定的一个。描述符(签名加返回类型) 最具体的方法是在运行时使用该方法来执行该方法 调度。
如果方法适用于子类型,则该方法适用 (§15.12.2.2),适用于方法调用转换(§15.12.2.3), 或者它是适用的变量arity方法(§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);
}
答案 1 :(得分:16)
Java中有许多重载的String.valueOf
方法。此外,在Java null
中有任何和所有类型,以便任何(不是原始的)可以是null
。
因此,当您致电(String.valueOf((Object)null)
时,您调用valueOf
方法,该方法将Object
用作null
显式转换为Object
。
在第二个示例中,您没有明确地将null
强制转换为任何特定类型,因此实际上您使用valueOf
调用char[]
方法会抛出NPE。
第二步搜索上一步中确定的类型 成员方法。此步骤使用方法的名称和类型 用于查找可访问的方法的参数表达式 适用的,即可以正确调用的声明 给定的论点。
可能有多种这样的方法,在这种情况下最多 选择特定的一个。描述符(签名加返回类型) 最具体的方法是在运行时使用该方法来执行该方法 调度。
在这种情况下,char[]
更具体而不是Object
,因此在没有明确演员null
时会调用它。
答案 2 :(得分:6)
虽然我已经接受了一个答案,但我想补充问题的确切答案,因为这两个答案集中在解释我走进的陷阱。
(Object)null
和null
之间的区别在于第一个的类型被强制为Object
,但第二个的类型不是,正如人们所能想到的那样,被迫Object
1}}。相反,它也可以是一个数组而不是一个对象。
所以结论是:将(Object)null
而不是null
作为参数传递给方法,以确保完全获取处理对象的方法而不是任何其他处理数组的方法。