java谜题(1)

谜题1,奇数性

public static boolean isOdd(int i ){
    return i%2==1;
}

当 i 是一个负奇数时,i % 2 等于-1 而不是1, 因此 isOdd 方法将错误地返回 false。为了防止这种意外,请测试你的方法在为每一个数值型参数传递负数、零和正数数值时,其行为是否正确。 

这个问题很容易订正。只需将 i % 2 与 0 而不是与1 比较,并且反转比较的含义即可: 

public static boolean isOdd(int i){ 
return i % 2 != 0;
}

如果你正在在一个性能临界(performance-critical)环境中使用isOdd 方法,那么用位操作符AND(&)来替代取余操作符会显得更好: 
public static boolean isOdd(int i){ 
return (i & 1) != 0;

}

谜题2,找零时刻

浮点数不够精确,只可用int或者BigDecimal类型做金钱计算。(另外单独说明)

谜题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);

}

}

我们计划打印1000,遗憾的是,它打印的是5。这里到底发生了什么呢? 
     问题在于常数MICROS_PER_DAY的计算“确实”溢出了。尽管计算的结果适合放入long中,并且其空间还有富余,但是这个结果并不适合放入int中。这个计算完全是以int运算来执行的,并且只有在运算完成之后,其结果才被提升到long,而此时已经太迟了:计算已经溢出了,它返回的是一个小了200倍的数值。从int提升到long是一种拓宽原始类型转换(widening primitive conversion),它保留了(不正确的)数值。这个值之后被MILLIS_PER_DAY整除,而MILLIS_PER_DAY的计算是正确的,因为它适合int运算。这样整除的结果就得到了5。 

那么为什么计算会是以int 运算来执行的呢?因为所有乘在一起的因子都是int数值。当你将两个int 数值相乘时,你将得到另一个int 数值。Java不具有目
标确定类型的特性,这是一种语言特性,其含义是指存储结果的变量的类型会影响到计算所使用的类型。 

通过使用long常量来替代int常量作为每一个乘积的第一个因子,我们就可以很容易地订正这个程序。这样做可以强制表达式中所有的后续计算都用long运
作来完成。尽管这么做只在MICROS_PER_DAY表达式中是必需的,但是在两个乘积中都这么做是一种很好的方式。相似地,使用long作为乘积的“第一个”数值也并不总是必需的,但是这么做也是一种很好的形式。在两个计算中都以lon数值开始可以很清楚地表明它们都不会溢出。下面的程序将打印出我们所期望的1000: 

public class LongDivision{ 
public static void main(String args[ ]){
final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000;
final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000;
System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY);
}

}


这个教训很简单:当你在操作很大的数字时,千万要提防溢出——它可是一个缄默杀手。即使用来保存结果的变量已显得足够大,也并不意味着要产生结果的计算具有正确的类型。当你拿不准时,就使用long运算来执行整个计算。

谜题4,初级问题

public class Elementary{ 
public static void main(String[] args){
System.out.println(12345+5432l);
}
}
System.out.println(12345+5432L); 

注意1和L(l)的区别.

谜题5,十六进制的趣事

public class JoyOfHex{ 
public static void main(String[] args){
System.out.println(
Long.toHexString(0x100000000L + 0xcafebabe));
}
}
十六进制最高位被置位了,为负数。

谜题6,多重转型

public class Multicast{ 
public static void main (String[] args){
System.out.println((int)(char)(byte) -1);
}
}

窄的整型转换成较宽的整型时符号扩展规则:如果最初的数值类型是有符号的,那么就执行符号扩展(即如果符号位

为1,则扩展为1,如果为零,则扩展为0);如果它是char,那么不管它将要被提升成什么类型,都执行零扩展。

了解上面的规则后,我们再来看看迷题:因为byte是有符号的类型,所以在将byte数值-1(二进制为:11111111)提

升到char时,会发生符号位扩展,又符号位为1,所以就补8个1,最后为16个1;然后从char到int的提升时,由于是

char型提升到其他类型,所以采用零扩展而不是符号扩展,结果int数值就成了65535。

如果将一个char数值c转型为一个宽度更宽的类型时,只是以零来扩展,但如果清晰表达以零扩展的意图,则可以考虑

使用一个位掩码:

Java代码

2 int i = c & 0xffff;//实质上等同于:int i = c ; 

如果将一个char数值c转型为一个宽度更宽的整型,并且希望有符号扩展,那么就先将char转型为一个short,它与

char上个具有同样的宽度,但是它是有符号的:

Java代码

3 int i = (short)c; 

如果将一个byte数值b转型为一个char,并且不希望有符号扩展,那么必须使用一个位掩码来限制它:

Java代码

4 char c = (char)(b & 0xff);// char c = (char) b;为有符号扩展 




System.out.println(12345+5432L); 

posted @ 2013-01-10 23:49  sqtds  阅读(273)  评论(0编辑  收藏  举报