1 java puzzler 94 应该优先使用库函数提供的方法。
package arkblue.javapuzzler.n94; import java.util.Arrays; import java.util.Collections; public class Shuffle { public static void shuffle(Object[] a) { Collections.shuffle(Arrays.asList(a)); } }
2 java puzzler 95
(1)操作符==的优先级大于?:
(2)?:操作符是从右向左结合的。
下例打印结果是false。
package arkblue.javapuzzler.n95; public class ChocolateCheck { public static void main(String[] args) { System.out.println(true ? false : true == true ? false : true); } }
3 java puzzler 1 判断奇数性
当取余操作返回一个非零的结果时,它与左操作数具有
package arkblue.javapuzzler.n1; public class OddTest { // 是错的,i=-1时,返回-1 public static boolean isOdd(int i) { return i % 2 == 1; } public static boolean isOddTwo(int i) { return i % 2 != 0; } public static boolean isOddThree(int i) { return (i & 1) != 0; } }
4 java puzzler 3
从int提升为long是一种拓宽原生类型转换(widening primitive conversion)
下面的代码演示了溢出:
package arkblue.javapuzzler.n3; public class OverFlow { public static void main(String args[]) { // 24 * 60 * 60 * 1000 * 1000 这行超过了整数的最大值 final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000; // 修改成 final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000; final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000; System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY); } }
5 java puzzler 12
package arkblue.javapuzzler.n12; public class Abc { public static void main(String[] args) { String letters = "ABC"; char[] numbers = { '1', '2', '3' }; System.out.println(letters + " easy as " + numbers); System.out.print(letters + " easy as "); // PrintStream 重载了char[] System.out.println(numbers); // String.valueOf 重载了char[] System.out.println(String.valueOf(numbers)); } }
5 java puzzler 14
Java 对在字符串字面常量中的Unicode 转义字符没有提供任何特殊处理。编译器在将程序解析成各种符号之前,先将Unicode
转义字符转换成为它们所表示的字符[JLS 3.2]。因此,程序中的第一个Unicode转义字符将作为一个单字符字符串字面常量("a")的结束引号,而第二个Unicode 转义字符将作为另一个单字符字符串字面常量("b")的开始引号。程序打印的是表达式"a".length()+"b".length(),即2。
package arkblue.javapuzzler.n14; public class EscapeRout { public static void main(String[] args) { // /u0022 是双引号的Unicode 转义字符 System.out.println("a/u0022.length() + /u0022b".length()); System.out.println("a/".length() + /"b".length()); } }
打印结果
2 16
6 java puzzler 18
(1)“在通过解码使用平台缺省字符集的指定byte 数组来构造一个新的String 时,该新String 的长度是字符集的一个函数,因此,它可能不等于byte 数组的长度。当给定的所有字节在缺省字符集中并非全部有效时,这个构造器的行为是不确定的”[Java-API]。
(2)J2SE 运行期环境(JRE)的缺省字符集依赖于底层的操作系统和语
package arkblue.javapuzzler.n18; import java.io.UnsupportedEncodingException; public class StringCheese { public static void main(String[] args) { byte bytes[] = new byte[256]; for (int i = 0; i < 256; i++) bytes[i] = (byte) i; String str = null; try { str = new String(bytes, "ISO-8859-1"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } for (int i = 0, n = str.length(); i < n; i++) System.out.println((int) str.charAt(i) + " "); } }
7 java puzzler 20
package arkblue.javapuzzler.n20; import java.io.File; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Me { public static void main(String[] args) { // replaceAll 的第一个参数是正则表达式 System.out.println(Me.class.getName().replaceAll(".", "/") + ".class"); // "//." 才能表示字符句点 System.out .println(Me.class.getName().replaceAll("//.", "/") + ".class"); // Pattern.quote 返回正则表达式,参数是精确匹配的欲替换字符 System.out.println(Me.class.getName().replaceAll(Pattern.quote("."), "/") + ".class"); System.out .println(Me.class.getName().replaceAll("//.", "/") + ".class"); // Matcher.quoteReplacement使用replacement的字面值作为替换值 System.out.println(Me.class.getName().replaceAll("//.", Matcher.quoteReplacement(File.separator)) + ".class"); System.out.println(Me.class.getName().replace(".", File.separator) + ".class"); System.out.println(Me.class.getName().replace('.', File.separatorChar) + ".class"); // 运行期间抛出异常,replacement string 是单独的反斜线,是无意义的 System.out.println(Me.class.getName().replaceAll(".", File.separator) + ".class"); } } // Pattern.quote 返回正则表达式,参数是精确匹配的欲替换字符 System.out.println(Me.class.getName().replaceAll(Pattern.quote("."), "/") + ".class"); } }
打印结果
//////////////////////////.class arkblue/javapuzzler/n20/Me.class arkblue/javapuzzler/n20/Me.class arkblue/javapuzzler/n20/Me.class arkblue/javapuzzler/n20/Me.class arkblue/javapuzzler/n20/Me.class arkblue/javapuzzler/n20/Me.class Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 1 at java.lang.String.charAt(String.java:558) at java.util.regex.Matcher.appendReplacement(Matcher.java:696) at java.util.regex.Matcher.replaceAll(Matcher.java:806) at java.lang.String.replaceAll(String.java:2000) at arkblue.javapuzzler.n20.Me.main(Me.java:36)
8 java puzzler25 15.14.2]:表达式j++的值等于j 在执行增量操作之前的初始值。
打印结果 0
package arkblue.javapuzzler.n25; public class Increment { public static void main(String[] args) { int j = 0; for (int i = 0; i < 100; i++) j = j++; System.out.println(j); } }
9 java puzzler 26 所有的int变量都小于或等于Integer.MAX_VALUE;下面代码导致死循环
package arkblue.javapuzzler.n26; public class InTheLoop { public static final int END = Integer.MAX_VALUE; public static final int START = END - 100; public static void main(String[] args) { int count = 0; for (int i = START; i <= END; i++) count++; System.out.println(count); } }
修改 for (long i = START; i <= END; i++)
10 java puzzler 27
问题在于(-1 << 32)等于-1 而不是0,因为移位操作符之使用其右操作数的低5 位作为移位长度。或者是低6 位,如果其左操作数是一个long 类数值[JLS15.19]。
下面程序陷入死循环
package arkblue.javapuzzler.n27; public class Shift { public static void main(String[] args) { int i = 0; while (-1 << i != 0) i++; System.out.println(i); } }
11 java puzzler 31 制造一个无限循环
short i = -1; while (int i= 0) { i >>>= 1; }
(1)i首先扩展为int型,short类型的-1,用0xffff表示,扩展为int,表示0xffffffff;执行算数右移,变成0x7fffffff,然后赋值给i;因为i是short类型,截断高两个字节,表示为0xffff,还是-1;
(2)复合赋值操作符包括*=、/=、%=、+=、-=、<<=、>>=、>>>=、&=、^=和|=。)有关混合操作符的一个不幸的事实是,它们可能会自动地执行窄化原始类型转换[JLS 15.26.2],
12 java puzzler 32
声明一个 i,j,使下面的语句变成无限循环
while (i <= j && j <= i && i != j) { }
Integer i = new Integer(0);
Integer j = new Integer(0);
(1)Java 的数字比较操作符(<、<=、>和>=)要求它们的两个操作数都是原始数字类型的(byte、char、short、int、long、float 和double)[JLS 15.20.1]。但是在5.0 版中,规范作出了修改,新规范描述道:每一个操作数的类型必须可以转换成原始数字类型[JLS 15.20.1,5.1.8]
(2)为Java 的判等操作符(==和!=)在作用于对象引用时,执行的是引用ID 的比较,而不是值的比较
13 javapuzzler 34
while (i != 0 && i == -i) { }
当int i = Integer.MIN_VALUE;
int i = 2^32;
上例可以无限循环
14 %和 * 的结合性是相等的
package arkblue.javapuzzler.n35; public class Clock { public static void main(String[] args) { int minutes = 0; for (int ms = 0; ms < 60 * 60 * 1000; ms++) if (ms % 60 * 1000 == 0) minutes++; System.out.println(minutes); } }
等价于 if ((ms % 60) * 1000 == 0)