【原創】JAVA中使人眼花撩亂的數字魔法

五月的深圳空氣中瀰漫起初夏的味道,淡淡的,暖暖的。春日裏不太張揚的陽光也摻入這股氣息...(煙哥好文采!)
這天,煙哥愉快的喝着霸氣芝士莓莓莓。一邊東張西望,尋找着能夠裝13的機會。一切正以下面這張圖這樣

這時,小劉出現了!沒錯,就是那個你們期待的小劉出現了!她拿着一本《XXXjava筆試指南》來找煙哥。
只見小劉嫺熟的打開這本書,望着整本書滿滿的筆記,煙哥不由猜想道:"小劉如此熱衷於學習,必定仍是單身。"想到這裏,煙哥不由更有回答的動力了(沒錯,我就是這種人!)。java

緩存問題

小劉翻到某一頁後,指出下面這樣一道題緩存

public static void main(String[] args){
 Integer a = 50;
 Integer b = 50;
 Integer c = 150;
 Integer d = 150;
 System.out.println(a==b);
 System.out.println(c==d);
}

輸出結果爲函數

true
false

而後詢問煙哥具體原因。
煙哥看完之後,心裏正(wei)直(suo)的笑了笑,內心想道:"這不是幾年前的老題目了麼,怎麼如今還在考!"
煙哥回答道:"其實很簡單,原理是下面這樣滴!"
JAVA編譯器編譯Integer a = 50的時候,被翻譯成-> Integer a = Integer.valueOf(50);
valueOf的源碼是下面這樣的學習

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
  }

看到了嘛,Integer內部有一個IntegerCache緩存。對於值範圍在-128到127之間的數,會進行緩存。所以a和b範圍在-128到127之間,因此指向的是同一個對象,因此判斷結果是true。而c和d在128以外,因此每次都是返回一個新對象,因此判斷結果是false
聽到這裏,小劉彷佛很滿意的準備打道回府。
"不行,怎麼能這樣讓小劉離開。我得多和小劉說說話!"
因而,煙哥說道:"小劉阿,其實java筆試裏關於數值方面的陷阱,能夠玩出不少花樣,你瞭解多少?"
很天然的,小劉的表情是下面這樣的
測試

越界問題

煙哥說道:"這樣吧,先問你一個問題。Math.abs(Integer.MIN_VALUE))的結果是正數仍是負數?"
小劉:"Math.abs是絕對值運算,結果應該是正數吧。"
煙哥:"不對,仍是負數。Integer的範圍爲-2147483648~2147483647。不過咱們先來看一眼abs函數的源碼,以下所示"翻譯

public static int abs(int a) {
    return (a < 0) ? -a : a;
}

煙哥:"看了源碼,其實很明顯,絕對值運算的原理是判斷這個數是否大於零,若是小於零則取負值。OK,回到咱們題目。Integer.MIN_VALUE,它的十六進制表示是 0x80000000。其符號位爲1,其他全部的位都是0。取負數(反碼+1)則爲 0x7fffffff+1,也就是 0x80000000。你會發現對Integer.MIN_VALUE取負值仍是自己。所以,結果仍是負數。"
小劉:"那你這套理論對LongShortByte都成立麼?"
煙哥:"是的,都是成立的,原理都同樣。你能夠回去測試一下以下代碼"3d

Short num =(short)Math.abs(Short.MIN_VALUE));
System.out.println(num);

小劉望着這些代碼,陷入了思考...
忽然,小劉回答道:"好像,以前我有看到一個題目是這樣的。是否存在一個數i,可使得i+1<i,這樣看來,這個i就是Integer.MAX_VALUE,由於加完1就溢出了變爲負值了。"
聽小劉說道這裏,煙哥換了一個角度問:"是否存在一個數,知足i != 0 && i == -i"
小劉想了下,機智的回答道:"其實仍是Integer.MIN_VALUE,緣由你剛纔說過了!"
唉,沒想到小劉領悟如此的快!code

浮點奧祕

煙哥感慨小劉領悟速度的同時,加大難度問道:"是否存在一個數,知足i==i+1?"
小劉忽然懵了,答道:"好像..彷佛..應該一個數永遠不會等於本身加一。"
看見小劉懵圈的眼神,煙哥只見本身裝13的目的已經達到,便再也不賣關子...
煙哥回答道:"有沒聽過一句話,無窮大加一個常數仍是無窮大!因此,下面的例子輸出爲true"對象

double i = Double.POSITIVE_INFINITY;
System.out.println(i == i+1);

小劉反懟煙哥,說道:"其實,無窮大減去一個常數也是無窮大。因此下面例子也是輸出爲true,並且無窮小也有相似的特性。"blog

double i = Double.POSITIVE_INFINITY;
System.out.println(i == i-1);

煙哥滿意的點了點頭,感慨小劉成長真快!
忽然,靈光一閃,煙哥補充道:"你知不知道有一個數能夠知足i!=i?"
小劉再次陷入了深思...嘴裏嘟囔道:"奇怪,還有一個數能夠本身不等於本身麼?"
望着小劉愁眉苦臉的眼神 ,煙哥答道:"對,有一個不是數值的值,它就是NaN,翻譯過來就是(Not a Number),所以下面的輸出是爲true!"

double i = Double.NaN;
System.out.println(i != i);

結局

在煙哥一陣裝13後,決定暴露本身的本性。問道:"小劉,你有對象了麼?"
小劉答道:"煙哥,你是個好人,然而我已經有對象了!"
"Boom!"
(本文完!)

相關文章
相關標籤/搜索