一. 表达式之谜
二. 字符之谜
三. 循环之谜
谜题24
byte是有符号的,范围是-128 - 127。而0x90是int类型。比较的时候,不相等。如果想让其相等,需要进行类型转换:(byte & 0xff) 或者 (byte)0x99。
谜题25
自增运算符对循环的影响。j = j++,先赋值。
谜题26
Integer.MAX_VALUE加一之后会变成Integer.MIN_VALUE,这对循环会有影响。可以考虑使用long来表示i变量,或者使用效率更高的i != Integer.MAX_VALUE。
谜题27
(-1 << 32)的结果是-1而不是0。对于int型的数据移位运算总是取右端数转换成2进制的低五位。对于long型的数据移位运算总是取右端数转换成2进制的低六位。32取低五位是0,因此结果是-1。如果右边的数是负数,同样保留低五(六)位,将其转换为正数。谜题28
while(i == i + 1) {}
当浮点数i足够大时候, i = i + 1。
相邻浮点数之间的距离被称为ulp(unit int the last place),一旦ulp超过2,加一将不会产生任何影响。
二进制浮点数算术只是一种近似。
谜题29
while(i != i) {}IEEE 754浮点算术保留了一个特殊的值:NaN(not a number)。double i = 0.0 / 0.0,double i = Double.NaN,任何浮点数操作,只要一个或多个操作数为NaN,那么结果是NaN。NaN不等于任何浮点数,包括它自身。NaN != NaN 。
谜题30
while(i != i + 0) {}i != i + 0,如果i是String类型。此时的+就不是算术加号了,被重载为字符串的连接。
谜题31
while(i != 0) {i >>>= 1;}还是在讲类型转换。当i为short类型的-1的时候,i >>>= 1,仍旧是-1:首先将short转换为int,然后在截取低位16。short,byte的任何负数最终都会转换为-1。而char不会,char是无符号的。谜题32
Integer i = new Integer(0);
Integer j = new Integer(0);
while(i <= j && i >= j && i != j){
}
包装类,当使用==运算符时候,并不是判断值相等,而是引用(兼容性考虑)。<=或者>= 都是值判断。
谜题33
while(i != 0 && i == -i) {}整数的边界问题0x8000 0000 表示最小的负数(Integer.MIN_VALUE),对其求相反数,仍是其本身。谜题34
final int START = 2000000000; int count = 0; for (float f = START; f < START + 65; f++) { count++; System.out.println(START + 65); }
浮点数精度问题START+50与START相等,当使用浮点数表示的时候。50比START的ulp距离(128)的一半还小。当超过ulp的距离的一半的时候,无限循环。谜题35
取余和乘除具有相同的优先级。
四. 异常之谜
谜题36
finally语句中的return语句会覆盖掉try语句中的。谜题37
该部分还需要进一步理解一个方法可以抛出的被检查异常集合是它所适用的所有类型声明要抛出的被检查集合的交集。
五. 类之谜
谜题46
函数重载的问题。JAVA重载解析过程:1. 选取所有可用的方法或者构造器;2. 从过程1中选取的方法或构造器中选择最精确的。一般而言:可以强制要求编译器选择一个精确的重载版本,将实参转型为形参所声明的类型。
谜题47
继承中静态域的问题。静态域由声明它的类及其所有子类共享。如果需要让每一个子类都具有某个域的单独拷贝,必须在每一个子类中声明一个单独的静态域。如果每一个实例都需要一个单独的拷贝,则可以在基类中声明一个非静态域。
谜题48
静态方法的问题。对静态方法的调用不存在任何动态分配机制。静态方法是编译时刻选定的,根据修饰符编译期类型选定的。静态方法不能被覆写,只能被隐藏。尽量使用类名来调用静态方法。谜题49
public class Elvis { public static final Elvis INSTANCE = new Elvis(); private final int beltSize; private static final int YEAR = Calendar.getInstance().get(Calendar.YEAR); private Elvis() { beltSize = YEAR - 1930; } public int beltSize() { return beltSize; } public static void main(String[] args) { System.out.println(INSTANCE.beltSize()); } }初始化的问题。final类型的静态域被初始化之前存在被读取的可能,此时该静态域只是所属类型的缺省值。final类型的域只有在初始化表达式是常量表达式时,才是常量。类的初始化循环有待进一步理解。
谜题50
instanceof的问题当instanceof左操作数为null时,返回false。当instanceof左右操作数都是类的时候,其中一个必须是另一个的子类型,否则编译错误。转型操作符的行为与instanceof相同,当转型操作的两种类型都是类时,必须其中一个是另一个子类型。
谜题51
class Point { protected final int x, y; private final String name; Point(int x, int y) { this.x = x; this.y = y; name = makeName(); // 3. 调用子类的方法。 } protected String makeName() { return "[" + x + "," + y + "]"; } public final String toString() { return name; } } public class ColorPoint extends Point{ private final String color; ColorPoint(int x, int y, String color) { super(x, y); //2. 转向父类的构造函数。 this.color = color; // 5. 初始化该属性。 } protected String makeName() { //4.在子类的构造函数结束前执行。 return super.makeName() + ":" + color; } public static void main(String[] args) { //1. 调用子类的构造函数。 System.out.println(new ColorPoint(1, 2 , "red")); } }构造函数调用了子类覆写的方法。实例初始化循环,可以采用惰性初始化。
谜题52
class Cache { static { initializedIfNecessary(); } private static int sum; public static int getSum() { initializedIfNecessary(); return sum; } private static boolean initialized = false; private static synchronized void initializedIfNecessary() { if (! initialized) { for (int i = 0; i < 100; i++) { sum += i; } initialized = true; } } } public class Client { public static void main(String[] args) { System.out.println(Cache.getSum()); } }同时使用了惰性初始化和积极初始化。初始化顺序对结果的影响。修改后的程序class Cache { private static final int sum = computeSum(); private static int computeSum() { int result = 0; for (int i = 0; i < 100; i++) { result += i; } return result; } public static int getSum() { return sum; } }
谜题53
讲述了私有构造器捕获惯用法。<span style="font-size:18px;">class Thing { public Thing(int i) { System.out.println("Thing:" + i); } } public class MyThing extends Thing { @SuppressWarnings("unused") private final int arg; public MyThing() { this(1);//可以调用其他类的方法获取返回值。 } private MyThing(int i) { super(i); arg = i; } }</span>
谜题54
静态方法调用时,实例不起作用。静态方法是属于类的。
谜题55
java语言规范不允许一个本地变量声明语句作为一条语句在循环中重复执行。一个本地变量声明作为一条语句,只能直接出现在一个语句块中(花括号中的)。for (int i = 0; i < 10; i++)
String str = "123";
这个编译不通过,修改正确为:for (int i = 0; i < 10; i++) {
Stirng str = "123";
}
六. 库之谜
谜题56
谜题57