下面的方法意图确定它那唯一的参数是否是一个奇数。这个方法能够正确运转吗?
public static boolean isOdd(int i){
return i % 2 == 1;
}
奇数可以被定义为被2整除余数为1的整数。表达式 i % 2 计算的是 i 整除 2 时所产生的余数,因此看起来这个程序应该能够正确运转。遗憾的是,它不能;它在四分之一的时间里返回的都是错误的答案。
为什么是四分之一?因为在所有的 int 数值中,有一半都是负数,而 isOdd 方法对于对所有负奇数的判断都会失败。在任何负整数上调用该方法都回返回 false ,不管该整数是偶数还是奇数。
这是 Java 对取余操作符(%)的定义所产生的后果。该操作符被定义为对于所有的 int 数值 a 和所有的非零 int 数值 b,都满足下面的恒等式:
(a / b) * b + (a % b) == a
换句话说,如果你用b整除a,将商乘以b,然后加上余数,那么你就得到了最初的值 a 。该恒等式具有正确的含义,但是当与 Java 的截尾整数整除操作符相结合时,它就意味着:当取余操作返回一个非零的结果时,它与左操作数具有相同的正负符号。
当 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;
}
总之,无论你何时使用到了取余操作符,都要考虑到操作数和结果的符号。该操作符的行为在其操作数非负时是一目了然的,但是当一个或两个操作数都是负数时,它的行为就不那么显而易见了。
分享到:
相关推荐
java中一些疑难问题的剖析,对初学java者有很好的帮助。
在JDK1.2中,Thread.stop、Thread.suspend以及其他许多线程相关的方法都因为它们不安全而不推荐使用了。下面的方法展示了你用Thread.stop可以实现的可怕事情之一
java解惑java解惑java解惑java解惑java解惑java解惑
一本很好的java参考书,帮助你解决java中的很多注意不到的问题。
Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑
这篇文档主要是介绍各种大家需要注意的java各种语法细节。希望对大家有所帮助。写的比较幽默。类似“十六进制的趣事”这种问题,估计在SSH大行其道的情况下,有些细节大家都不太关注了。
java中最容易被忽略的地方. 博文链接:https://justjavac.iteye.com/blog/175252
表达式之谜,符号之谜,循环之谜,异常之谜,类之谜,库之谜,各种谜题。
《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》
Java解惑.pdf Java解惑.pdf Java解惑.pdf Java解惑.pdf
Java解惑中文版 Java解惑 java健壮程序
JAVA解惑.pdf JAVA解惑.pdf JAVA解惑.pdf
与java相关的的学习,适合初学者,可以看看
Java PUZZLE Java 解惑 Java PUZZLE Java 解惑 Java PUZZLE Java 解惑Java PUZZLE Java 解惑 Java PUZZLE Java 解惑 Java PUZZLE Java 解惑
比较容易混淆的java面试题,看看对笔试面试有一定的帮助。
JAVA解惑,你面包括一些java经典的问题。
《Java解惑》 布洛克 著;陈昊鹏 译 扫描清晰带目录,仅供参阅,请支持正版
JAVA解惑(PDF) Java学习中所涉及到的一些疑难杂症。