谜题11:最后的笑声

如何打印'H'+'a'使之输出是Ha

第一种方式:
StringBuffer sb = new StringBuffer();
sb.append('H');
sb.append('a');
System.out.println(sb);
第二种方式:
System.out.printf("%c%c",'H','a');//使用的是JDK5
第三种方式:
System.out.println(""+'H'+'a');//这种方式自认为更常见

谜题12:ABC

在输出一个char数组时,如要显示数组内容,则要将char数组转换成一个字符串,就要调用String.valueOf(char[])的方法

谜题13:动物庄园

final String pig = "length: 10";
final String dog = "length: "+pig.length();
System.out.println("Animals are equal:"+pig == dog);
上面的代码实际比较的是("Animals are equal:"+pig) == dog,所以很明显返回的是false
如果要比较pig == dog,有以下两种方式:
第一种方式:System.out.println("Animals are equal:"+(pig == dog));
第二种方式:System.out.println("Animals are equal:"+pig.equals(dog));


谜题14:转义字符的溃败

System.out.println("a\u0022.length()+\u0022b".length());
\u0022表示的是”,一个双引号
上面的代码相当于:System.out.println("a".length()+"b".length()),输出结果为2
如果真要打印包含最前最后的双引号中间内容,则要进行这样处理:
System.out.println("a\".length()+\"b".length()),这时的输出结果是16(字符串长度)

总结:

在字符串和字符字面常量中优先选择的是转义字符序列,而不是unicode转义字符

谜题15:令人晕头转向的Hello

Unicode转义字符必须是良构的,即使出现在注释中也是如此、

在javadoc注释中,应该使用HTML实体转义字符来代替Unicode转义字符

工具应该确保不将window文件名置于所生成的java源文件的注释中。

总之,要确保字符\u不在一个合法的Unicode转义字符上下文之外出现,即使在注释中也是如此,在机器生成的代码中要特别注意此问题。


谜题16:行打印程序

\u000A,表示换行,如果在注释中出现这样的字段,编译时会直接换行。如果其后不是可编译的代码,则会编译出错

正确输出换行操作

char c ='\n';
System.out.println(c);

但是这仍然是一个有问题的程序:它是平台相关的,例如UNIX,它将打印两个完整的行分隔符,但是在其他平台上,例如Windows,它就不会产生这样的行为

总之:Unicode转义字符绝对会产生混乱,除非确实是必要的,否则就不要使用Unicode转义字符


谜题17:嗯?

只有在你要向程序中插入用其他任何方式都无法表示的字符时,Unicode转义字符才是必需的,除此之外的任何情况都应该避免使用。Unicode转义字符降低了程序的清晰度,并且增加了产生bug的可能性

谜题18:字符串奶酪

每当要将一个byte序列转换成一个String时,你都在使用一个字符集,不管是否显示指定了它,如果想让你的程序行为可预知,那么在每次使用字符集时都明确指定它。

例如:

byte bytes[] = new byte[255]
for(int i = 0; i < 256 ; i++){
byte[i] =(byte)i;
}
 不指定:String str = new String(bytes)指定:String str = new String(bytes, "ISO-8859-1");

做同样的输出:

for(int i=0, n=str.length();i<n;i++){
System.out.print((int)str.charAt(i)+" ");

}

不指定的方式,在运行的时候是具有不保证性的,因为String(byte[])构造器,它的规范是在通过解码使用平台默认字符集的指定的byte数组来构造一个新的String时,该新String的长度是字符集的一个函数,因为,它可能不等于byte数组的长度,当给定的所有字节在默认字符集中并非全部有效时,这个构造器的行为是不确定的。所以不推荐

指定的方式,是可以保证从0到255输出的~


谜题19:漂亮的火花(块注释符)

在使用块注释符时(/* */)要注意内部不要包含有*/这样结束字符,否则编译不通过

块注释不能嵌套

注释掉代码段的最好方式是使用单行的注释序列

块注释不能可靠地注释掉代码块,应该用单行的注释序列来代替,对语言设计都来说,应该注意可嵌套的块注释并不是一个好主意,它们强制编译器去解析块注释内部的文本,而由此引发的问题比它所解决的问题更多

谜题20:我的类是什么

package com.javapuzzlers;
public class Me{

public static void main(String[]args){
System.out.println(Me.class.getName().replaceAll(".", "/")+".class");
}

}

上面的代码所运行的结果将是///.class

问题在于String.replaceAll接受了一个正则表达式作为它的第一个参数,而并非接受了一个字符序列字面变量。正则表达式“.”可以匹配任何单个字符。

如果想要正常输出想要的结果com/javapuzzlers/Me.class

则可以有下面两种方式:

System.out.println(Me.class.getName().replaceAll("\\.","/")+''.class");
System.out.println(Me.class.getName().replaceAll(Pattern.quote("."),"/")+".class");

该程序的另一个问题是:其正确的行为是与平台相关的,并不所有的文件系统都使用斜杠符号来分隔层次结构的文件名组成部分。

谜题21:我们的类是什么?镜头

继上个谜题续:

System.out.println(Me.class/getName()/replaceAll("\\.", File.separator)+".class");
在unix上,将会打印com/javapuzzlers/Me.class,因为unix的文件分隔符是斜杠的
在window上,将会报错,因为window的文件分隔符是反斜杠的
如何解决这问题呢?
JDK5.0有两种方式:
第一种方式:
System.out.println(Me.class.getName().replaceAll("\\.",Matcher.quotoReplacment(File.separator))+".class");
第二种方式:System.out.println(Me.class.getName().replace(".",File.separatorChar)+".class");
如果是较早版本的java,可以这样做:
System.out.println(Me.class.getName().replace(".",File.separator)+".class");

谜题22:URL的愚弄

在java代码中单行加入:http://www.google.com;

是可以编译通过的,这个URL是一个语句标号, 这是Java编程语言中鲜为人知的特性,这个程序标注了个表达式语句 ,它是合法的,但是它没什么用处。

这个用法让我想到初学java时在跳出循环时使用的标识符,在一个for循环前面指定一个标识比如search:,然后当找到该值时break search;则会跳出循环。

谜题23:不劳而获


1、第一个知识点:
Random rnd = new Random();

rnd.nextInt(2);返回的是均等地健在在从0(包含)到指定的数值(不包含)之间的一个int数值

2、第二个知识点:

在switch语句中,第执行完一个case必须执行break操作

3、第三个知识点:

StringBuffer sb = new StringBuffer('M');//程序编译时返回的是一个具有初始容量77的空字符串缓冲区,因为StringBuffer(String),StringBuffer(int),作为char类型的数据会更倾向于转换成int类型

所以真要一个M转换成字符串,则需要这样用:StringBuffer sb = new StringBuffer("M");