谜题11:最后的笑声
来看下面这段程序将打印什么?
public class LastLaugh{
public static void main(String[] args){
System.out.print("H" + "a");
System.out.print('H' + 'a');
}
}
该程序看起来好像是用两种方式连接了H和a,那么你会认为这个程序将会打印HaHa。但是运行后,打印的却是Ha169,那么,为什么会产生这样的行为呢?
毫无疑问,对于第一个“System.out.print("H" + "a");”来说,打印的确实是Ha,它的参数是表达式"H" + "a",执行的是一个字符串连接。而第二个"System.out.print('H' + 'a');",'H'和'a'是字符型字面常量,所以执行的就是加法而不是字符串的连接。当编译器在计算'H' + 'a'时,是通过我们熟知的拓展原生类型转换,将两个具有字符型数值的操作数提升为int数值来实现加法运算。因此,根据ASSIC表我们能够查到'H'的assic码为72,'a'的assic码为97,因此在进行加法运算后(72+97),打印出来的是169。
站在语言的立场上,若干个char和字符串的相似之处是虚幻的。语言所关心的是char是一个无符号16位原生类型整数,仅此而已。对类库来说就不仅如此了,类库包含了许多可以接受char类型参数的方法,将其作为Unicode字符处理。那么,我们就可以使用类库来解决这个谜题了:
StringBuffer sb = new StringBuffer();
sb.append('H');
sb.append('a');
System.out.println(sb);
这样做,我们就能正常打印出我们想要的内容了,但这样做显然是比较麻烦的,一条简单打印语句居然要写成4条语句来实现,其实,我们还有一种更简单的方法。我们都知道利用""来表示一个字符串,并且我们只要把打印的参数也转换成字符串,那么我们也能够正常打印出我们想要的内容了,这样,我们就可以利用一个空串(" ")来强制+操作符来执行字符串连接操作:
System.out.println(" " + 'H' + 'a');
这种惯用法可以确保子表达式都被转型为字符串。但不难看出,它自身可能会引发某些混淆,例如下面这行代码:
System.out.println("2+2=" + 2 + 2);
很显然,这行代码打印的绝对不是2+2=4而是2+2=22,因为子表达式都被转型为字符串了。
如果使用的是JDK 5.0,还可以使用System.out.printf("%c%c",'H','a');的方法来打印,学过C语言就知道这种打印形式与C语言几乎是一样的。
总而言之,在使用字符串连接操作符时要格外小心。当且仅当+操作符的操作数中至少有一个是String类型时才会执行字符串连接操作;否则,就会执行加法运算。如果要连接的数值没有一个是字符串类型的,那么可以有这几种解决方法:预置一个空字符串;将第一个数值用String.valueOf显示地转换成一个字符串;使用一个字符串缓冲区(StringBuffer);或者使用printf格式输出的方法(JDK版本是5.0)。