摘自《Java解惑》。这些问题都很经典,可以细细品味。
今天讲解的问题如下,奇数性问题、长整除问题、找零时刻、多重转型、Dos Equis。
奇数性
1. public class Odd {
2. public static void main(String[] args) {
3. System.out.println("1是奇数吗?"+isOdd(1));
4. System.out.println("2是奇数吗?"+isOdd(2));
5. System.out.println("-1是奇数吗?"+isOdd(-1));
6. }
7. public static boolean isOdd(int i){
8. return i % 2 == 1;
9. }
10. }
分析
这是Java对取余操作符(%)的定义所产生的。isOdd方法对于对所有负奇数的判断都会失败。在任何负整数上调用该方法都回返回false,不管该整数是偶数还是奇数。
建议
无论你何时使用到了取余操作符,都要考虑到操作数和结果的符号。
解决
方案一:
1. public static boolean isOdd(int i){
2. return i % 2 != 0;
3. }
方案二:
1. public static boolean isOdd2(int i){
2. return (i & 1) != 0;
3. }
长整除
1. public class LongDivision {
2. publicstatic void main(String[] args) {
3. final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000;
4. final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
5. System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);
6. }
7. }
分析
当两个int数值相乘时,将得到另一个int数值。因此最后的结果是int数值,从而导致溢出。
建议
当在操作很大的数字时,千万要提防溢出。
解决
方案:强制表达式中的所有后续计算都用long运算来完成
1. public class LongDivision2 {
2. public static void main(String[] args) {
3. final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
4. final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000;
5. System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);
6. }
7. }
找零时刻
1. public class Change {
2. public static void main(String[] args) {
3. System.out.println(2.0-1.1);
4. }
5. }
分析
并不是所有的小数都可以用二进制浮点数精确表示。
建议
在需要精确答案的地方,要避免使用float和double。对于货币计算,要使用int、long、BigDecimal。一定要用BigDecimal(String)构造器,而千万不要用BigDecimal(double)。后一个构造器将用它的参数的精确值来创建一个实例。
解决
方案一:JDK5.0或更新版本,可以使用printf方法
1. public class Change2 {
2. public static void main(String[] args) {
3. System.out.printf("%.2f",2.0-1.1);
4. }
5. }
方案二:使用BigDecimal类
1. public class Change3 {
2. public static void main(String[] args) {
3. BigDecimal bigNum1 = newBigDecimal("2.0");
4. BigDecimal bigNum2 = newBigDecimal("1.1");
5. System.out.println(bigNum1.subtract(bigNum2));
6. }
7. }
初级问题
1. public class Elementary {
2. public static void main(String[] args) {
3. System.out.println(12345+5432l);
4. }
5. }
分析
“5432l”中的“l”是小写的“L”。
建议
在long类型常量中,一定要用大写的L,千万不要使用小写的l。类似地,要避免使用单个l字母作为变量名。
解决
方案:
1. public class Elementary {
2. public static void main(String[] args) {
3. System.out.println(12345+5432L);
4. }
5. }
多重转型
1. public class Multicast {
2. public static void main(String[] args) {
3. System.out.println((int)(char)(byte)-1);
4. }
5. }
分析
如果最初的数值类型是有符号的,就执行符号扩展。如果是char,那么不管它将要被转换成什么类型,都执行零扩展。
Dos Equis
1. public class DosEquis {
2. public static void main(String[] args) {
3. char x = 'X';
4. int i = 0;
5. System.out.println(true?x:0);
6. System.out.println(false?i:x);
7. }
8. }
分析
如果第2个和第3个操作数具有相同的类型,那么它就是条件表达式的类型。如果一个操作数的类型是T,T表示byte、short、char,而另一个操作数是一个int类型的常量表达式,它的值可以用类型T表示。否则,将对操作数类型进行二进制数字提升,而条件表达式的类型就是第2个和第3个操作数被提升之后的类型。
建议
最好在表达式中使用类型相同的第2个和第3个操作数。
登录 | 立即注册