問題一:
byte b1 = 3,b2 = 4,b;
b = b1+b2;
b = 3+4;
哪一句是編譯失敗的?為什麼?
答案:
b = b1+b2;是有問題的。
因為變量相加,會首先看類型的問題,當最終把結果指派時也會考慮類型的問題。(short和byte類型運算結果會自動轉換為int型,系統會擔心損失精度,是以會報錯,不讓運作!)
但是當常量相加時,會首先做加法,然後看結果是否在指派的資料類型範圍内,如果不在才會報錯。
代碼驗證:
我們可以很明顯的看到類型不對!
程式正常的運作出來了!
其實這個問題涉及到了一個知識點——變量相加和常量相加的差別!
對于其他資料類型的使用也是類似的!
問題二:
System.out.println("hello" + 'a' + 1);
System.out.println('a' + 1 + "hello");
這兩句有差別嗎?
答案:
有很大的差別!
當字元串和其他資料做+時,結果是字元串類型,這裡的+不是加法運算,而是字元串連接配接符。
但是當多個其他資料和字元串做+時,會先讓前面的資料進行加法運算,再和字元串進行連接配接操作。
(說到底就是順序的問題!)
代碼驗證:
問題三:
short s = 1;s = s+1;
short s = 1;s+=1;
上面的兩行代碼有沒有問題?如果有問題在哪?
答案:
第一個有問題,第二個沒有問題!
第一行代碼在于s+1運算之後得到的資料是int型,是以類型不相容,系統會擔心損失精度,是以會報錯,不讓運作!(其實和問題一的問題有點類似!)
第二行代碼關鍵在于,擴充的指派運算符實際上隐含了一個強制類型轉換。
s += 1不是等價于s = s + 1;而是等價于s = (s的資料類型)(s+1);
代碼驗證:
我們可以很明顯的看到類型不對!
當換回s+=1的時候,程式并沒有報錯,可以正常的運作!
可以推廣到其他的資料類型和運算符:
問題四:
資料類型預設轉換的時候:
byte、short、char—int—long—float—double
但是我們知道long占8個位元組,float占4個位元組。
你就不會感到疑惑嗎?四個位元組的float怎麼裝得下八個位元組的long,資料不會溢出嗎?那是怎麼實作的呢?
答案:
首先float類型資料是裝得下long類型資料的:
float資料範圍:
- 負數範圍:-3.4×1038~-1.4×10-45
- 正數範圍:1.4×10-45~3.4×1038
long資料範圍:
- -263~263-1
3.4x10^38 > 2x10^38 > 2x8^38 = 2x2^3^38 > 2x2^114 >2^63-1
是以float類型是完全裝得下long類型資料的。
那麼為什麼裝得下呢?
關鍵就在于底層實作的方式不同。
簡單解釋:
long類型就類似于00000000 00000000 00000000... ...直接存!
float類型類似于數學裡面的科學記數法
是以float類型資料存儲資料的範圍大。
補充:
float的具體存儲方式:
float類型數字在計算機中用4個位元組存儲。遵循IEEE-754格式标準:
一個浮點數有2部分組成:底數m和指數e
底數部分 使用二進制數來表示此浮點數的實際值
指數部分 占用8bit的二進制數,可表示數值範圍為0-255
但是指數可正可負,是以,IEEE規定,此處算出的次方必須減去127才是真正的指數。
是以,float類型的指數可從-126到128
底數部分實際是占用24bit的一個值,但是最高位始終為1,是以,最高位省去不存儲,在存儲中占23bit
科學計數法。
格式:
SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
S表示浮點數正負
E指數加上127後的值得二進制資料
M底數
舉例:
17.625在記憶體中的存儲
首先要把17.625換算成二進制:10001.101
整數部分,除以2,直到商為0,餘數反轉。
小數部分,乘以2,直到乘位0,進位順序取。
在将10001.101右移,直到小數點前隻剩1位:
1.0001101 * 2^4 因為右移動了四位
這個時候,我們的底數和指數就出來了
底數:因為小數點前必為1,是以IEEE規定隻記錄小數點後的就好。是以,此處的底數為:0001101
指數:實際為4,必須加上127(轉出的時候,減去127),是以為131。也就是10000011
符号部分是整數,是以是0
綜上所述,17.625在記憶體中的存儲格式是:
01000001 10001101 00000000 00000000