Java解惑讀書筆記1

1。奇偶判斷,應該用i%2!=0爲奇數來判斷,因爲當爲負數的時候%2的結果可能會是-1,用i%2==1會出錯。(i&1)!=0使用低位是否爲1來判斷是否奇偶。


2。小數精確計算。java中的float和double都是不太精確的,容易造成精度丟失,比如System.out.println(2.00-1.10);結果不是0.9而是0.8999999999999999。一次我們可以用long或者int來代替浮點數(比如0.9我們可以用200-110表示來計算,最後結果除以100.0F)。或者使用BigDecimal


3.int 相乘溢出!這個最常見了,在項目中經常出現多少天等於多少毫秒之類的,如果這樣算long s = 25 * 24 * 3600 * 1000,最後s=-2134967296,怎麼會溢出呢,原因是這幾個都是整形,最大值是2147483647,所以25天就溢出了而24天是正常的,怎麼辦?把25改爲25L即可,它會強制轉化爲long型再計算,如果我把1000改爲1000L,像這樣long s = 25 * 24 * 3600 * 1000L,可能會溢出嗎?還是會,如果前面的數字超出整形就溢出,所以應該把左邊的第一個數設置爲long型。


4.字面常量,所以的字面常量都是int型,不管是10進制還是16進制,除非以L結尾表示他是long型。


5.窄數字拓展到寬數字的拓展。如果是char類型,一定是無符號拓展,因爲char沒有負數。其他的,如果之前是正數則無符號拓展,如果是負數則有符號拓展。記住這點即可。

6.這個和上面的相似。(byte)0x90 == 0x90 嗎?不等於,因爲左邊的會被拓展成int,而byte這個是負數,會有符號拓展,最後結果是負數和0x90當然不相等,可以加一個掩碼0xFF把前面的負數去除即可 (byte)0x90 & 0xFF == 0x90,

按位與0xFF的意思是隻保留數字的低8位,高位按0處理。


7.三元表達式(:?)。討論起表達式的值,a?b:c這樣的,如果b或者c一個是int或者long字面常量,而另一個是char byte short等變量,則表達式類型爲char byte short。如果沒有一個是字面常量,則拓展爲最寬的作爲表達式類型。舉例

char x = 'X';
int i = 65;
System.out.println(true ? x : 65);// X
System.out.println(false ? x : 65);// A。注意這裏不是65
System.out.println(true ? i : x);// 65
System.out.println(false ? i : x);// 88。注意這裏不是X


8.+=符合運算。x+=i和x=x+i是不等效的,因爲會涉及到類型的轉化。如果x是窄的,i是寬的,x+=i編譯不報錯但結果可能會溢出,而x=x+i則編譯不通過。所以儘量不要在複合運算左邊用byte char short類型,容易溢出。舉例。

int i=10033333;
byte b = 12;
//編譯無措,結果會溢出
b += i;
//編譯錯誤 :cannot convert from int to byte
//b = b + i;


9.++i和i++區別,這個一般人都知道,不說了

10.Integer.MAX_VALUE+1=Integer.MIN_VALUE。因爲int是有符號數,最大值爲0x7FFFFFFF,+1變爲0x80000000,這個是負數最小值。這樣看int好像是一個循環,超過最大值便成了最小值了。

11。移位.x<<y。如果x是byte,char ,short會被拓展爲int再移位,怎麼拓展參照前面介紹的拓展方法,如果y超過32會取對32的模,也就是說最多隻能移32位,如果x是long型,則y會對64取模。舉例

System.out.println(-1 << 31);// -2147483648 向左移31%32=31位
System.out.println(-1 << 32);// -1 向左移32%32=0位
System.out.println(-1 << 33);// -2 向左移33%32=1位
System.out.println(-1 << 1);// -2 向左移1%32=1位

System.out.println(-1L << 63);// -9223372036854775808 向左移63%64=63位
System.out.println(-1L << 64);// -1 向左移64%64=0位
System.out.println(-1L << 65);// -2 向左移65%64=1位



12。double和float有正無窮大和負無窮大的定義,所以double d = 1.0/0.0;這是可以編譯和運行的(int和long不行),結果d爲Double.POSITIVE_INFINITY。而Double.POSITIVE_INFINITY + 1 == Double.POSITIVE_INFINITY。還有一個Double.NEGATIVE_INFINITY表示負無窮大。

13.double和float有個NaN,它不等於任何數字,包括自己,double d = 0.0/0.0,d即Double.NaN

14.自動拆箱,這個最常見了,目前1.6版本支持。

// 為了兼容以前版本,1.5不會自動拆箱
System.out.println(new Integer(0) == new Integer(0));// false
// 1.4編譯非法,1.5會自動拆箱
System.out.println(new Integer(0) == 0);// true


15.爲什麼-0x00000000==0x00000000、-0x80000000== 0x80000000.只需要知道,最高位爲符號位,0表示整數,1表示負數。內存中是補碼錶示所有數字的,正數的補碼就是其二進制碼,而負數的補碼需要計算,計算方法:將其絕對值按位取反。然後+1即可。舉例。-0x80000000的絕對值爲0x80000000,按位取反爲0x7FFFFFFF,然後加1等於0x80000000,所以-0x80000000== 0x80000000。

16.Math.abs可能會負數,System.out.println(Math.abs
(Integer.MIN_VALUE));// -2147483648。原因可以abs計算方法:return (a<0)?-a:a,可參照15,知道Integer.Min_VALUE == -Integer.MIN_VALUE.同理Long也類似.

17。不要使用基於減法的比較器。爲何?可能會溢出啊,比如
int x = -2000000000;
int y = 2000000000;
顯然x是小於y的,如果按照x-y>0來判斷,x-y最後是正的,結果就錯了。
可使用比較型,如
基於整型的比較器的實現一般使用如下的方式來比較:

public int compare(Integer i1, Integer i2) {
return (i1 < i2 ? -1 : (i1 == i2 ? 0 : 1));
}


18. int i=-2147483648與int i=-(2147483648)?
前面的式子可以編譯通過,後面的編譯不通過,爲啥,因爲int型字面常量,最大值爲2147483647.所以int i=-(2147483647)就可以了。

[b]
小結:前面這個18個問題都是數值表達式方面的,在平時使用的時候,只要注意別溢出即可。[/b]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章