讀<<Java解惑>>後的碎嘴子(第三章)

第三章--循環問題

24.
for (byte b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
	if (b == 0x90)
	System.out.print("Joy!");
}
結果是什麼也沒打,不要被迷惑,十六進制的90雖然是8位,產生了byte本身也是8位能裝下不溢出的錯覺,但是byte作爲有符號整數表示範圍是-128~127,負數最高位是1
總結:本身沒有什麼特別的,但本條內容再現了bloch大師最具特色的頭腦風暴

25.
int j=0;
for(int i=0;i<100;i++)
   	j = j++;
System.out.println(j);

結果是0而不是100,這個猛一看還是挺糊弄人的,其實本質把j++當作一個表達式看就明白了,它永遠會返回未自增前的0值,這樣重複了100次,把j++改成++j肯定可以解決,但是IDE會嘲笑你在做一個很二的操作
總結:再基礎的東西都會使人犯錯,不要小看這些基本元素

26.
int count = 0;
for(int i=Integer.MAX_VALUE-100; i<=Integer.MAX_VALUE; i++)
       count++;
System.out.println(count);
結果是100?還是101?結果是死循環,原因很簡單,當i被加成Integer.MAX_VALUE時,再加一次就溢出了,直接變成了Integer.MIN_VALUE,如此往復
總結:不要打這些邊界值的想法

27.
int i = 0;
while (-1 << i != 0)
   	i++;
System.out.println(i);

結果是32?結果還是死循環,int的-1二進制表示是32個1,當i==32時-1<<32的結果是-1而不是0,原因就一句,任何類型不可能移走和原類型本身一樣的位數(如int型不能移動32位,最多31位,long不能移動64位,最多63位)
總結:bit位移什麼的,最討厭了

28.
while(i==i+1){}

i爲何值,死循環成立?答案有很多,之一是無窮大的浮點數如Double.POSITIVE_INFINITY,按照數學的說法無窮大+1還是無窮大,按照大師的說法則是當一個浮點數足夠大,在其上加減值是可能不會影響返回值的,這想想是可以理解的,不能把思考整數的習慣思維用在浮點數上
總結:二進制浮點數只是返回近似值

29.
while(i != i){}

i爲何值,死循環成立?答案是Double.NaN,一句話它不等於任何值,包括它自己
總結:在含0乘除計算中,尤其是除數或者被除數有0,或0.0時,根據int和double等參與類型,會相應返回Double.POSITIVE_INFINITY,Double.NaN等值,放在實際業務方法裏帶來的bug足以讓你喝一壺(這個曾經可是有着深刻的體會)

30.
while (i != i + 0) {}

i爲何值,死循環成立?附加條件是i不能是float或double,答案是任何字符串,這樣+符號會被重載,數字0也會被當作字符串從而和i拼接到一起
總結:大師也懂得輕鬆一刻

31.
while (i != 0) {
	i >>>= 1;
}

i爲何值,死循環成立?答案是任何short,byte的負數,如short i = -1,二進制爲16個1,重點在於short,byte,char進入循環會有一個神奇的int轉換,i會被當作32個1來操作,經過無符號右移最高位變成了0,然後賦值回i(別忘了i是short類型),所以還會有一次窄化賦值,只保留了後16位,等於還是16個1,被右移的高16位被無情的扔掉了
總結:不要在short,byte,char上執行這樣的複合賦值,小心自動窄化

32.
while (i <= j && j <= i && i != j) {}

i爲何值,死循環成立?答案是任何基本包裝類型,如Integer i = new Integer(0);Integer j = new Integer(0);不過當然只限於5.0版本以後,這裏auto-boxing在起作用,當遇到<=這樣的比較符號時,會自動將對象解包成基本類型,

這樣前兩個表達式爲true,但是當遇到==或!=時便不會解包,比較將是內存位置,畢竟Integer是new出來的,這樣i!=j會返回true
總結:如果改成Integer i = 0;Integer j = 0;i!=j還成立嗎?大師對於new是否存在,使用值相等或引用相等的規律並沒有作頭腦風暴,自行參考auto-boxing內部原理吧

33.
while (i != 0 && i == -i) {}

i爲何值,死循環成立?答案是Integer.MIN_VALUE或Long.MIN_VALUE,爲什麼沒有byte和short?關鍵還是自動轉型,本條在大師的敘述中還有很多值得學習思考的地方
總結:一元減號操作符用在一個非數值型上是非法的,沒有任何浮點數等於其符號位反轉之後的值,牢記有符號整數採用的是補碼計算法,以及各個整數表示範圍中,負數比正數要多一個,因爲0被排除了,這樣多出來的那個負數便有了其特殊性

34.
int START = 2000000000;
int count = 0;
for (float f = START; f < START + 50; f++)
         count++;

完畢後count會是什麼呢?這一看就是有問題的,誰也不會使用float作爲循環索引,根據原來的經驗,浮點數足夠大,加1並不會使它改變,所以答案是死循環嗎?答案是0,循環沒有執行,因爲f < START + 50不成立,很簡單,f並不是2000000050
總結:可以順便複習一下for的執行順序,float和short這樣的東西,除非特殊環境下(嵌入式?),否則不應該出現在的任何應用裏了

35.
int minutes = 0;
for (int ms = 0; ms < 60*60*1000; ms++){
if (ms % 60*1000 == 0)
	minutes++;
   }
完畢後minutes會是什麼呢?答案是60000,大師不教你也能看出來了,取餘(%)的優先級和乘法(*)優先級是一樣的,順序會從左到右計算
總結:不要吝嗇用括號,最後一條讓你從無數個死循環中輕鬆一下,總體本章還是比較有意思的
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章