谜题1:奇数性
public static boolean isOdd(int i){
return i % 2 == 1;
}
题目:对于负数如果用X%2=1来判断是否为奇偶并不成立
解决办法:x&0X01=0 或者 x%2=0来 判断
谜题2:找零时刻
public class Change{
public static void main(String args[]){
System.out.println(2.00 - 1.10);
}
}
题目: 程序输出0.8999999999999999
原因: 并不是所有的小数都可以用二进制浮点数来精确表示的。
解决办法: new BigDecimal("2.00").subtract(newBigDecimal("1.10")));
谜题3:长整除
public class LongDivision{
public static void main(String args[]){
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);
}
}
题目: 程序输出5
原因: 这个计算完全是以int运算来执行的,并且只有在运算完成之后,其结果才被提升到long,
而此时已经太迟了:计算已经溢出了,它返回的是一个小了200倍的数值。
解决办法 :
final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
finallong MILLIS_PER_DAY = 24L *60 * 60 * 1000;
谜题4:初级问题
public class Elementary{
public static void main(String[] args){
System.out.println(12345+5432l);
}
}
题目:程序输出17777
原因:5432l
解决办法: 写程序注意关键字与数字。 0与O, 1与l
谜题5:十六进制的趣事
public class JoyOfHex{
public static void main(String[] args){
System.out.println(
Long.toHexString(0x100000000L + 0xcafebabe));
}
}
题目:cafebabe
原因:
0xffffffffcafebabeL
+ 0x0000000100000000L
---------------------
0x00000000cafebabeL
解决办法:Long.toHexString(0x100000000L+ 0xcafebabeL));
谜题6:多重转型
public class Multicast{
public static void main (String[] args){
System.out.println((int)(char)(byte) -1);
}
}
那么就执行符号扩展;如果它是char,那么不管它将要被转换成什么类型,都执行零扩展。
解决办法: System.out.println((int)(short)(char)((byte)-1));
谜题7:互换内容
public class CleverSwap{
public static void main(String[] args){
int x = 1984; // (0x7c0)
int y = 2001; // (0x7d1)
x^= y^= x^= y;
System.out.println("x= " + x + "; y= " + y);
}
}
忽略。
谜题8:Dos Equis
public class DosEquis{
public static void main(String[] args){
char x = 'X';
int i = 0;
System.out.println(true ? x : 0);
System.out.println(false ? i : x);
}
}
题目:程序输出:X88
原因:一个操作数的类型是char,另一个的类型是int。在两个表达式中,int操作数都是0,
它可以被表示成一个char。然而,只有第一个表达式中的int操作数是常量(0),而
第二个表达式中的int操作数是变量(i)。因此,第2点被应用到了第一个表达式上,它
返回的类型是char,而第3点被应用到了第二个表达式上,其返回的类型是对int和char
运用了二进制数字提升之后的类型,即int。
1, 如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类型。换句话说
你可以通过绕过混合类型的计算来避免大麻烦。
2,如果一个操作数的类型是T,T表示byte、short或char,而另一个操作数是一个int类型的
常量表达式,它的值是可以用类型T表示的,那么条件表达式的类型就是T。
3,否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第二个和第三个操作数被提升之后的类型。
解决办法:
谜题9:半斤
short x = 0;
int i = 123456;
复合赋值编译将不会产生任何错误:
x += i; // 包含了一个隐藏的转型!
x = i+1 //编译不过
题目:
原因: 复合赋值表达式自动地将它们所执行的计算的结果转型为其左侧变量的类型。如果结果的类型与该变量的类型相同,
那么这个转型不会造成任何影响。然而,如果结果的类型比该变量的类型要宽,那么复合赋值操作符将悄悄地执行,
一个窄化原始类型转换。
解决办法:请不要将复合赋值操作符作用于byte、short或char类型的变量上。在将复合赋值操作符作用于int类型的变量上时,
要确保表达式右侧不是long、float或double类型。在将复合赋值操作符作用于float类型的变量上时,要确保表达式
右侧不是double类型。这些规则足以防止编译器产生危险的窄化转型。
谜题10:八两
Object x = "Buy ";
String i = "Effective Java!";
简单赋值是合法的,因为 x + i 是String类型的,而String类型又是与Object赋值兼容的:
x = x + i;
复合赋值是非法的,因为左侧是一个Object引用类型,而右侧是一个String类型:
x += i;
题目:
原因:复合赋值操作符要求两个操作数都是原始类型的,例如int,或包装了的原始类型,例如Integer,但是有一个例外:
如果在+=操作符左侧的操作数是String类型的,那么它允许右侧的操作数是任意类型,在这种情况下,该操作符执行的是
字符串连接操作。简单赋值操作符(=)允许其左侧的是对象引用类型,这就显得要宽松许多了:你可以使用它们来表示
任何你想要表示的内容,只要表达式的右侧与左侧的变量是赋值兼容的即可。