Java中的類型轉換在Java編碼中具有重要的作用。首先,來了解下數據類型的基本理解:數據類型是用來描述數據的種類,包括其值和基于其值基礎上的可進行的操作集合。Java中數據類型主要分為兩大類:基本數據類型和引用數據類型。
基本數據類型共有8種,分別是:布爾型boolean, 字符型char和數值型byte/short/int/long/float/double。由于字符型char所表示的單個字符與Ascii碼中相應整形對應,因此,有時也將其劃分到數值型中。引用類型具體可分為:數組、類和接口。因此,本文中Java類型轉換的總結也將分為基本數據類型和引用數據類型兩個方面展開。
一、基本數據類型的類型轉換
基本數據類型中,布爾類型boolean占有一個字節,由于其本身所代碼的特殊含義,boolean類型與其他基本類型不能進行類型的轉換(既不能進行自動類型的提升,也不能強制類型轉換), 否則,將編譯出錯。
1.基本數據類型中數值類型的自動類型提升
數值類型在內存中直接存儲其本身的值,對于不同的數值類型,內存中會分配相應的大小去存儲。如:byte類型的變量占用8位,int類型變量占用32位等。相應的,不同的數值類型會有與其存儲空間相匹配的取值范圍。具體如下所示:
圖中依次表示了各數值類型的字節數和相應的取值范圍。在Java中,整數類型(byte/short/int/long)中,對于未聲明數據類型的整形,其默認類型為int型。在浮點類型(float/double)中,對于未聲明數據類型的浮點型,默認為double型。
將一個int型的3賦給一個byte型的變量c,居然編譯正確,這是為什么呢?
原因在于:jvm在編譯過程中,對于默認為int類型的數值時,當賦給一個比int型數值范圍小的數值類型變量(在此統一稱為數值類型k,k可以是byte/char/short類型),會進行判斷,如果此int型數值超過數值類型k,那么會直接編譯出錯。因為你將一個超過了范圍的數值賦給類型為k的變量,k裝不下嘛,你有沒有進行強制類型轉換,當然報錯了。但是如果此int型數值尚在數值類型k范圍內,jvm會自定進行一次隱式類型轉換,將此int型數值轉換成類型k。如圖中的虛線箭頭。這一點有點特別,需要稍微注意下。
在其他情況下,當將一個數值范圍小的類型賦給一個數值范圍大的數值型變量,jvm在編譯過程中俊將此數值的類型進行了自動提升。在數值類型的自動類型提升過程中,數值精度至少不應該降低(整型保持不變,float->double精度將變高)。
還有一個地方需要注意的是:char型其本身是unsigned型,同時具有兩個字節,其數值范圍是0 ~ 2^16-1,因為,這直接導致byte型不能自動類型提升到char,char和short直接也不會發生自動類型提升(因為負數的問題),同時,byte當然可以直接提升到short型。
2.基本數據類型中的數值類型強制轉換
當我們需要將數值范圍較大的數值類型賦給數值范圍較小的數值類型變量時,由于此時可能會丟失精度(1講到的從int到k型的隱式轉換除外),我們稱之為強制類型轉換。
將一個值為3的int型變量a賦值給byte型變量b,發生編譯錯誤。這兩種寫法之間有什么區別呢?
區別在于前者3是直接量,編譯期間可以直接進行判定,后者a為一變量,需要到運行期間才能確定,也就是說,編譯期間為以防萬一,當然不可能編譯通過了。此時,需要進行強制類型轉換。強制類型轉換所帶來的結果是可能會丟失精度,如果此數值尚在范圍較小的類型數值范圍內,對于整型變量精度不變,但如果超出范圍較小的類型數值范圍內,很可能出現一些意外情況。
如下經典例子:
1packagecom.corn.testcast;23publicclassTestCast {45publicstaticvoidmain(String[] args) {6inta = 233;7byteb = (byte) a;8System.out.println("b:" + b);//輸出:-239}1011}
為什么結果是-23?需要從最根本的二進制存儲考慮。
233的二進制表示為:24位0 + 11101001,byte型只有8位,于是從高位開始舍棄,截斷后剩下:11101001,由于二進制最高位1表示負數,0表示正數,其相應的負數為-23。
3.進行數學運算時的數據類型自動提升與可能需要的強制類型轉換
1packagecom.corn.testcast;23publicclassTestCast {45publicstaticvoidmain(String[] args) {6bytea = 3 + 5;//編譯正常 編譯成 3+5直接變為87intb = 3, c = 5;8byted = b + c;//編譯錯誤:cannot convert from int to byte910bytee = 10, f = 11;11byteg = e + f;//編譯錯誤 +直接將10和11類型提升為了int12byteh = (byte) (e + f);//編譯正確13}1415}
當進行數學運算時,數據類型會自動發生提升到運算符左右之較大者,以此類推。當將最后的運算結果賦值給指定的數值類型時,可能需要進行強制類型轉換。