《Java解惑》书摘

例子1:关于char数组的输出
 1 System.out.println("H" + "a");//输出:Ha
 2 System.out.println(‘H‘ + ‘a‘);//输出:169
 3 System.out.println("" + ‘H‘ + ‘a‘);//输出:Ha
 4 System.out.println("//////////////////");
 5 System.out.println("2 + 2 = " + 2 + 2);//输出:2 + 2 = 22
 6 System.out.println("2 + 2 = " + (2 + 2));//输出:2 + 2 = 4
 7 System.out.println("//////////////////");
 8 char[] char1 = {‘1‘, ‘2‘, ‘3‘};
 9 Object char2 = new char[] {‘1‘, ‘2‘, ‘3‘};
10 System.out.println(char1);//输出:123
11 System.out.println(char2);//输出:[C@55e83f9
12 System.out.println("test-" + char1);//输出:test-[C@55e83f9
13 System.out.println("test-" + char1.toString());//输出:test-[C@55e83f9
14 System.out.println("test-" + String.valueOf(char1));//输出:test-123
15 System.out.println("//////////////////");

例子2:
 1 Random random = new Random();
 2     StringBuffer sBuffer = null;
 3     switch(random.nextInt(2)) {
 4         case 1:sBuffer = new StringBuffer(‘A‘);
 5         case 2:sBuffer = new StringBuffer(‘B‘);
 6         default:sBuffer = new StringBuffer(‘C‘);
 7     }
 8     sBuffer.append(‘a‘);
 9     sBuffer.append(‘b‘);
10     sBuffer.append(‘c‘);
11     System.out.println(sBuffer);//输出:abc
12 }

这段程序有三个BUG:

  1. Random.nextInt(int n)方法的使用错误:
    先看下这个方法的API:
    public int nextInt(int n)
    返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值(不包括)之间均匀分布的 int 值。
    所以,此处应改为:switch(random.nextInt(3)) {
  2. case子句中没有break语句:
    导致前面的赋值被后面的赋值覆盖。
  3. StringBuffer类的构造方法使用错误:
    StringBuffer不支持传入参数为字符(char)的构造方法,应改为传入字符串(String),
    所以,应改为:sBuffer = new StringBuffer("A");

例子3:会死循环的代码
 1  //死循环1
 2         int start1  = Integer.MAX_VALUE-1;
 3         for(int start7=start1; start7<=start1+1; start7++) {
 4             System.out.println("loop..");
 5         }
 6         //死循环2
 7         double start2 = 1.0 / 0.0;
 8         double start3 = Double.POSITIVE_INFINITY;//与上句等价,可替代
 9         while(start2 == (start2+1)) {
10             System.out.println("loop..");
11         }
12         //死循环3
13         double start4 = 0.0 / 0.0;
14         double start5 = Double.NaN;//与上句等价,可替代
15         while(start4 != start4) {
16             System.out.println("loop..");
17         }
18         //死循环4
19         String start6 = "test";
20         while(start6 != (start6+0)) {
21             System.out.println("loop..");
22         }
23         //死循环5
24         byte start7 = -1;//死循环
25 //      short start7 = -1;//死循环
26 //      int start7 = -1;//循环32次
27 //      long start7 = -1;//循环64次
28         int count = 0;//循环次数
29         while(start7 != 0) {
30             start7 >>>= 1;
31             System.out.println("loop..");
32             count++;
33         }
34         System.out.println("循环次数 = " + count);
35         //死循环6
36         int start8 = Integer.MIN_VALUE;
37 //      Long start8 = Long.MIN_VALUE;
38         while(start8 != 0 && start8 == -start8) {
39             System.out.println("loop..");
40         }

补充说明:

  1. 关于Infinity和NaN(死循环2和3)
     1 double d = 1.0 / 0;                  
     2 System.out.println(d);             //输出:Infinity  
     3 System.out.println(d + 1);         //输出:Infinity  
     4 System.out.println(d == d + 1);    //输出:true
     5  
     6 d = 0.0 / 0;  
     7 System.out.println(d);             //输出:NaN  
     8 System.out.println(d + 1);         //输出:NaN  
     9 System.out.println(d == d + 1);    //输出:false
    10  
    11 System.out.println(Double.NaN == Double.NaN);//输出:false
    12 Double a = new Double(Double.NaN);
    13 Double b = new Double(Double.NaN);
    14 System.out.println(a.equals(b));//输出:true
  2. 关于Java的自动窄化原生类型转换(死循环5)
    分析 short start7 = -1; 和 start7 >>>= 1;这两句代码:
    在执行移位操作时,第一步是将start7提升为start7nt类型,因为所有的算术操作都会对short,byte,char类型的操作数执行这样的提升;
    这种提升是拓宽了原生类型,没有信息的损失,执行的是符号扩展,start7的值提升后是0xffffffff,start7>>>1之后得到的是0x7fffffff;
    将这个值再存入start7中的时候,为了将int数值存入short变量,Java自动执行了可怕的窄化原生类型,直接把高16位截掉,剩下(short)0xffff,又回到了起点,从而导致了死循环。
    这提醒了我们,不要在short,byte,char类型上使用复合赋值操作符,很容易出问题,而且这种隐性的窄化类型转换,在丢失信息的同时,结果也可能是灾难性的。
  3. 关于Java中的特殊值(死循环6)
    Java使用2的补码的算术运算是不对称的。
    对于每一种有符号的整数类型(byte、short、int和long),负的数值总是比正的数值多一个,这个多出来的数值总是这个类型所能表示的最小值;
    对Integer.MIN_VALUE取负值并不会改变它的值,对这个值取负值将会产生溢出,但是Java自动忽略了这种溢出;同理对Long.MIN_VALUE等也是如此。
 
 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。