java puzzlers [更新至14.04.15]

解惑1:奇偶性

  奇偶性判断可用&运算代替取余运算:

    偶数:(i & 1) == 0;

    奇数:(i & 1) != 0;

解惑2:找零时刻

System.out.println(2.0 - 1.1);    //输出0.8999999999999999

  二进制浮点不适合货币计算,它不能将0.1或10的其他任何负次幂精确表示为一个有限长度的二进制小数,只能表示为最靠近它的临近值。1.1不能被精确表示为一个double,因此2.0减去1.1的临近值就得到输出结果。

  解决方法可以将小数化为相应的整数进行计算,或者使用Java在java.math包中提供的API类BigDecimal,且必须使用参数类型为String的构造函数,上述代码可表示为:

System.out.println(new BigDecimal("2.0").subtract(new BigDecimal("1.1"))); //输出0.9

解惑3:长整数

long a = 24 * 60 * 60 * 1000 * 1000;
long b = 24L * 60 * 60 * 1000 * 1000;
System.out.println(a);            //输出500654080
System.out.println(b);            //输出86400000000    
System.out.println(Integer.MAX_VALUE);  //输出2147483647
System.out.println(Long.MAX_VALUE);    //输出9223372036854775807

  当操作数字很大时,要提防溢出。如上述代码,a虽然是long类型,但其赋值号右边的运算均以int运算来执行,在运算完成之后才提升为long型,而计算过程中已溢出(整型最大值为2^31-1 = 2147483647)。而b的第一个因子为long型,可使得每一个乘积的第一个因子均为long型,因此可以强制表达式所有后续计算都用long运算,且计算结果不会溢出(长整型最大值为2^63-1 = 9223372036854775807)。

解惑4:初级问题

  注意区分 54321 和 5432l 。后者为long型值为5432,为了区分,在long类型字面值常量中,建议用大写的L表示。

解惑5:十六进制的趣事

System.out.println(Long.toHexString(0x100000000L + 0xcafebabe));    //cafebabe
System.out.println(Long.toHexString(0x100000000L + 0xcafebabeL));   //1cafebabe

  十六进制和八进制字面常量的最高位被置为则它们为负数。第一行代码中0xcafebabe是int常量,它的最高位被置位,因此它是一个负数。运算时左边是long类型,右边是int类型,Java将使int提升为long类型,而int是有符号的整数类型,所以这个转换执行时符号扩展,因此右操作数被提升为0xffffffffcafebabeL,高32位是-1,而左边的long类型操作数高32位是1,因此相加后便只剩下低32位。解决办法如第二行代码,将第二个操作数表示为long类型即可。

解惑6:多重转型

System.out.println((int)(char)(byte)-1);  //输出65535

  遵循一条规则:若最初的数值类型是有符号的,就执行符号扩展;若它是char类型,那么不管它要被转换成什么类型,都执行零扩展。代码中-1原本是32位的int类型,其补码32位都是置位的,将其窄化为8位byte类型时,直接将低8位之外的所有位砍掉,剩下8位都置位的byte,仍表示-1。因为byte是有符号的类型,所以转换为16位char类型时会发生符号扩展,所以结果16位都被置位了,数值等于2^16-1=65535。而从char转化为32位的int类型时执行零扩展,因此int类型数值也等于65535即输出结果。

原文地址:https://www.cnblogs.com/honghuzidelaoren/p/3642140.html