在阅读this question时,我想起了我在第一次学习java时编写的程序中的一个错误,这个错误让我永远定位并且基本上归结为以下行为:
String s1 = "This was a triumph";
String n1 = null;
System.out.println(s1 + n); // prints "This was a triumphnull"
类似行为的一些其他值得注意的例子(以及令人困惑的反例):
// "nullThis was a triumph", coercion happens commutatively
System.out.println(n1 + s1);
// as per above question, println explicitly converts null Strings to "null"
System.out.println(n1);
// similar result
System.out.println(String.valueOf(n1));
// NullPointerException (!!); null not silently converted to "null"
// note that this is the kind of thing I expected to occur for the other examples
// when I wrote the buggy code in the first place
System.out.println(n1.toString());
虽然我认为我在技术上理解这种行为,但我绝对不会了解它,所以我的问题是:
修改
到目前为止,我很欣赏这些答案,但我只是想澄清一下,我的困惑很大程度上源于null Strings在这方面的处理方式与其他null对象的区别。例如:
Integer i1 = 42;
Integer n2 = null;
// Both produce NullPointerExceptions:
Integer.valueOf(n2);
System.out.println(i1 + n2);
我还想再强调NullPointerException是我期望的那种行为,这就是为什么我对null /" null"字符串转换首先。
答案 0 :(得分:3)
只有对象有方法。 null
不是一个对象;它没有方法。任何调用null
方法的尝试都会引发NullPointerException
。这有点类似于您尝试调用3.toString()
时所获得的内容,尽管它是运行时错误而不是编译时。
您在null
转换为"null"
所有特殊情况空引用的过程中给出的示例,以尝试提供更友好的接口。他们可以这样做,因为它们不是null
上的方法调用;他们可以进行内置x == null? "null" : x.toString()
等额外处理。这类似于System.out.println(3)
失败时可以调用3.toString()
的原因。
null整数的处理通过自动装箱工作,这是一种与打印和字符串连接中处理null的机制完全无关的机制。
当一个Integer(或其他7个原始包装类型之一)出现在需要原始int的上下文中时,编译器会自动插入Integer.valueOf
调用来执行转换。 Integer.valueOf
没有空值的安全默认值;虽然"null"
是null
的明显字符串形式,但对于调试输出非常有用,将空整数强制转换为0
或任何其他值都不太有用,而且容易出错。< / p>
答案 1 :(得分:2)
1
。这是一个设计选择,由String&amp; amp;从JDK1.0开始支持StringBuffer类(参见http://docs.oracle.com/javase/6/docs/api/java/lang/String.html等),这是自1996年1月21日以来 - 它支持使用+
运算符连接从那时起。在J2SE 5.0(2004年9月30日),也称为JDK 1.5,StringBuilder(非线程安全,但速度更快 - +
现在开始使用它而不是StringBuffer),自动装箱和泛型(带擦除)是补充 - 整个范式从使用反射的元编程转变为模板编程,而不是那么明显的铸造解决方案。 (参见例如https://codegolf.stackexchange.com/questions/28786/write-a-program-that-makes-2-2-5 - Java解决方案使用整数缓存中毒和装箱/拆箱来实现这个不太令人惊讶的结果)
String.java
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
Objects.java
public static String toString(Object o) {
return String.valueOf(o);
}
PrintStream.java
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
StringBuilder.java
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
等。 (Java src.zip,JDK v8)
几乎所有处理打印和toString转换的Java库方法都以这种方式处理null(即调用String.valueOf(),从而将其转换为文字“null”String)。另请注意,+
的concat也可以这样工作,因为它在编译期间转换为库调用(调用StringBuilder.append(Object o))。
2
。在空对象引用上显式调用#toString()仍然会导致NPEx,因为尝试调用其上的任何其他方法。
3
。 (是的,我知道没有第3部分)有趣的时间,尝试执行,例如
System.out.println( ((String)null).toString() );
(显然失败了),然后
System.out.println( ((String)null).valueOf((String)null).toString() ); // works?! why!?
扰流器:
静态方法。