这里列举几个Java中看似正确而容易出错的地方。
谜题1:奇数性
判定一个数是否为奇数,应用i % 2 != 0;不要用1来判断,因为有负数。
public class OddNumber {
public static void main(String[] args) {
System.out.println(isOdd1(-5));
System.out.println(isOdd2(-5));
System.out.println(isOdd3(-5));
System.out.println((20.0 - 11) / 10);
}
// 错误,不能用1判断,因为有负数
public static boolean isOdd1(int i) {
return i % 2 == 1;
}
// 正确
public static boolean isOdd2(int i) {
return i % 2 != 0;
}
// 正确
public static boolean isOdd3(int i) {
return (i & 1) != 0;
}
}
谜题2:找零时刻
有些小数不能用浮点数准确的表示
public class Change {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(2.00 - 1.10);// 结果为0.8999999999999999,而不是0.9,因为1.1不能用二进制浮点数精确的表示。
System.out.println((20.00 - 11) / 10);// 0.9
System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));// 0.90
}
}
谜题3:长整除
public class LongDivision {
public static void main(String[] args) {
final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;// 86400000000
final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY / MILLIS_PER_DAY);// 5,因为计算乘积的时候是按int计算的,超过int范围就会溢出了
final long MICROS_PER_DAY2 = 24L * 60 * 60 * 1000 * 1000;// 计算乘积的时候是按long计算的
final long MILLIS_PER_DAY2 = 24 * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY2 / MILLIS_PER_DAY2);// 1000
}
}
谜题6:多重转型
转型分为有符号转型和无符号转型,负数转为char就要有符号转型。,有一条很简单的规则能够描述从较窄的整型转换成较宽的整型时的符号扩展行为:如果最初的数值类型是有符号的,那么就执行符号扩展;如果它是char,那么不管它将要被转换成什么类型,都执行零扩展。
public class Multicast {
public static void main(String[] args) {
System.out.println((int) (char) (byte) -1);
// -1的二进制表示为32个1,int->byte,保留低8位,仍为-1;byte->char,由于byte有符号,char无符号,非负
// 所以要进行符号扩展(高位都添1),此时为16个1,结果为2的16次方-1,即65535;char->int,0扩展,高位添0,65535
}
}
谜题8:条件语句
如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类型。换句话说,你可以通过绕过混合类型的计算来避免大麻烦。
• 如果一个操作数的类型是T,T 表示byte、short 或char,而另一个操作数是一个int 类型的常量表达式,它的值是可以用类型T 表示的,那么条件表达式的类型就是T。
• 否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第二个和第三个操作数被提升之后的类型。
public class DosEquis {
public static void main(String[] args) {
char x = 'X';
int i = 0;
System.out.println(true ? x : 0);
System.out.println(true ? x : i);
}
}
谜题9:简单赋值与复合赋值表达式
- 1. short x = 0;
int i = 123456;
x += i; 包含了一个隐藏的转型
x = x + i;编译错误
- 2. Object x = "Buy ";
String i = "Effective Java!";
x = x + i; 简单赋值是合法的,因为 x + i 是String 类型的,而String 类型又是与Object赋值兼容的。
x += i;复合赋值是非法的,因为左侧是一个Object 引用类型,而右侧是一个String类型