昨天提到了一個奇怪的現象:
byte num = 128;
如上撰寫,妳的IDE將會在128底下亮出紅線,並說:「Type mismatch: cannot convert from int to byte」
今天就會來探討一下為什麼會發生這個奇怪的現象,不過在進入正題之前,想先談談何謂字面常量(literal constant)
昨天談到了基本型別(primitive type),其實被宣告為基本型別的變數所儲存的值就是各種字面常量,字面常量本身就代表了最純粹的數值,沒有經過記憶體位址的包裝,1就是1,2就是2。不過字面常量就只有我們日常生活使用的十進位(decimal)數字嗎?當然不止,還有十六進位(hexadecimal)、八進位(octet)、二進位(binary):
以上這些都是可以在Java程式中表達的字面常量,而且也都等於我們所謂的10這個數值。
欸,那還有一個字元(char)勒? 它是怎麼被儲存的? 電腦真的會存進abcd嗎?
實際上在Java,字元骨子裡是一個16 bits範圍的正數值,每個數值會再透過轉換轉成我們所看到的文字,所以當我們如下指派時:
int num = 'A';
num會變成65的int數值(JLS5.1.2),神奇吧。所以字元就像是一個蘿蔔一個坑,每個數字會代表一個文字,再查表對應出代表的文字(Unicode Table)
最後提點一下,昨天雖然有提到String字串不是基本型別,可是妳應該有注意到我們指派給String型別變數的也是像字面常量的值,其實沒錯!我們在等號右邊給它的字串也是一種字面常量,但字串比較特別一點,之後有機會再討論。
好了,該進入正題了~ 到底為什麼JVM要說我們給byte變數一個int字面常量勒?
答案就是,就是這樣...沒有為什麼,這就是Java在字面常量上的潛規則,只要我們直接打出數字的數值,它預設就是int的型態。而之所以byte num = 127會可以編譯成功是因為Java有自動針對byte, short, char, int常數narrowing conversion的功能(JLS5.2)
整數的常量會自動視為int型態,浮點數呢? 浮點數則是自動視為double型態,所以以下會編譯不過哦:
float fNum = 1.5;
可是我就是想要存1.5到float型別的變數怎麼辦? 這時候就有2種辦法了:
float fNum01 = 1.5f;
float fNum02 = (float)1.5;
第一種辦法是從字面常量下手,如果我們希望表示出float型態的浮點數,就得在最後面加上一個"f";
第二種辦法是使用Java的轉型(cast)語法,在值的前面用括號包住我們想轉成的型別名稱,就可以強制轉過去了。這個轉型水也是有點深度...之後可能需要花點篇幅說明,因為並不是可以無腦轉型的,尤其之後又有非基本型別的狀況時。
其實在整數也會有這樣的情況,由於數字預設是int型別,那如果我們寫下了一個超出int型別範圍的數值,並預計用一個long型別的變數來裝,要怎麼做到勒? 答案就是:
long num = 2147483648L;
在整數數值的最後面加上"L",就會把常量轉換為long型態了。
好了,我們只剩最後一個部分要講了,就是運算時常量的潛規則。
byte n1 = 1;
byte n2 = 2;
byte n3 = n1 + n2;
以上程式碼在第三行會出錯,詭異吧。這是因為Java預設在進行運算時,若運算元是小於int的型別,會先自動轉化為int型別後,再進行運算。所以只要有加減乘除的運算,最後結果一定最小會是int的型別!那下面的話呢:
int n1 = 1;
long n2 = 2;
int n3 = n1 + n2;
這樣的話第三行也還是最出錯,因為現在最大的型別變成long了,這時Java會先把所有型別都提升到long,再進行運算。這種特性稱為自動提升(promote)。
最後來個逗趣的東西:
int nn = 1 + 'A';
試試看nn會等於多少吧。
這篇有點長,來做個小結:
天啊我把Java講得好複雜哈哈,而且根本還沒進到物件@@