《Java 解惑》笔记

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Java 解惑》笔记相关的知识,希望对你有一定的参考价值。

 《Java 解惑》里都是一些编程时容易忽略的细节,却也蛮有意思的,所以将里面的内容稍作整理,简略地概括一下:

 1.奇数性

   在编程的时候经常会遇到要判断传进来的参数是否为奇数,而且容易惯性地认为判断余数是否为1即可,如下代码:

      public static boolean isOdd ( int i ) {

        return i % 2 == 1

      }

   这段程序在四分之一的时间里返回的都是错误的答案

   因为在所有的 int 数值中,有一半都是负数,而 isOdd 方法对于对所有负奇数的判断都会失败。在任何负整数上调用该方法都回返回false ,不管该整数是偶数还是奇数。这是 Java 对取余操作符(%)的定义所产生的后果。该操作符被定义为对于所有的 int 数值 a 和所有的非零 int 数值 b,都满足下面的恒等式:
      (a / b) * b + (a % b) == a

   当 i 是一个负奇数时,i % 2 等于-1 而不是1, 因此 isOdd 方法将错误地返回 false。

   这个问题很容易订正。只需将 i % 2 与0 而不是与1 比较,并且反转比较的含义即可:
      public static boolean isOdd(int i){
        return i % 2 != 0;
      }

 2.找零时刻

   请考虑下面这段话所描述的问题:
   Tom 在一家汽车配件商店购买了一个价值$1.10 的火花塞,但是他钱包中都是两美元一张的钞票。如果他用一张两美元的钞票支付这个火花塞,那么应该找给他多少零钱呢?下面是一个试图解决上述问题的程序,它会打印出什么呢?
        public class Change{
          public static void main(String args[]){
            System.out.println(2.00 - 1.10);
          }
        }

    这段代码输出的结果可并不是我们所期望的0.9,而是0.899999999999。这个问题在于 并不是所有的小数都可以用二进制浮点数来精确表示。浮点运算在一个范围很广的值域上提供了很好的近似,但它通常不能产生精确的结果。二进制浮点对于货币计算是非常不合适的,因为他不可能将0.1-- 或者10的其它任何次负幂精确地表示为一个长度有限的二进制小数。

    解决这个问题可以使用执行精确小数运算的BigDecimal。注意:一定要用BigDecimal ( String ) 构造器,而千万不要用BigDecimal ( double ) 。正确使用BigDecimal,程序就可以打印出我们所期望的结果0.90:
      import java.math.BigDecimal;
        public class Change1{
          public static void main(String args[]){
            System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));
          }
        }

    总之, 在需要精确答案的地方,要避免使用float 和double;对于货币计算,要使用int、long 或BigDecimal。对于语言设计者来说,应该考虑对小数运算提供语言支持。一种方式是提供对操作符重载的有限支持,以使得运算符可以被塑造为能够对数值引用类型起作用,例如BigDecimal。另一种方式是提供原始的小数类型,就像COBOL 与PL/I 所作的一样。

  3.字符问题

    •字符串连接的优先级不应该和加法一样。这意味着重载 + 操作符来执行字符串连接是有问题的。
    • 还有就是,对于不可修改的类型,例如String,其引用的等价性比值的等价性更加让人感到迷惑。也许 == 操作符在被应用于不可修改的类型时应该执行值比较。要实现这一点,一种方法是将 == 操作符作为equals方法的简便写法,并提供一个单独的类似于System.identityHashCode的方法来执行引用标识的比较。

以上是关于《Java 解惑》笔记的主要内容,如果未能解决你的问题,请参考以下文章

《Java解惑》读书笔记

《Java解惑》读书笔记

Java解惑六:库之谜

CryptoAPI 中的 CryptImportKey 接受 hPubKey 为 0 来导入加密的会话密钥

RSACryptoServiceProvider <-> CryptImportKey 等效性

C# PInvoke CryptImportKey 因“指定的类型无效”而失败