java包裝類老是讓人疑惑 它與值類型究竟是怎麼樣一種關係? 本文將以int和Integer爲例來探討它們的關係java
java值類型有int short char boolean byte long float double程序員
除此以外的類型皆爲引用類型 引用類型和值類型的區別你們都很熟悉 在這裏就很少說了c#
引用類型和值類型有一個很重要的區別 那就是引用類型繼承Object類 值類型不是jvm
而java不少泛型容器都要求類型繼承Object 調用虛方法要求必須是引用類型 很明顯這些值類型不知足這個要求 怎麼辦? 包裝類應運而生函數
包裝類有Integer Short Char Boolean Byte Long Float Double和上文的值類型是對應的spa
既然包裝類是引用類型 那麼他就應該能夠傳遞到別的方法被修改設計
public static void change(Integer a) { a *= 6; } public static void main(String[] args) { Integer integer = new Integer(5); change(integer); System.out.println(integer); }
然而 以上程序輸出的結果是5 跟下文代碼的結果是相同的 這是爲何?code
public static void change(int a) { a *= 6; } public static void main(String[] args) { int integer = 5; change(integer); System.out.println(integer); }
這就得從包裝類的設計講起了 前文說過 包裝類是爲了可以彌補值類型的缺陷而設計的對象
有了包裝類後 對於一個整數的表達就出現了int和Integer這兩個類型 一個是值類型一個是引用類型 這會讓程序員在使用過程當中產生困擾blog
爲了消除這種困擾 java在設計時就儘量地減小它們的區別 讓包裝類表現得如同值類型 因而就出現了上文的結果
這種區別減小是經過編譯器完成 若是咱們查看編譯好的字節碼 就會看到上文的Integer實際上是這樣工做的
public static void change(Integer a) { a = Integer.valueOf(a.intValue() * 6); } public static void main(String[] args) { Integer integer = new Integer(5); change(integer); System.out.println(integer); }
a*=6的結果返回了一個新的Integer對象
因此也就不可能修改傳入的Integer的值了 就算要修改 Integer這個類的成員是final修飾 仍是沒法修改
而後我還發現了一點Object強制轉換爲int
Object obj = new Integer(5); int a = (int)obj;
在編譯器處理後 實際上是這樣的 這也進一步說明引用類型和值類型徹底是兩個世界的東西
Object obj = new Integer(5); int a = ((Integer)obj).intValue();
題外話:
對於java的值類型和包裝類的設計 我十分不喜歡
java中一切都是對象 值類型除外
對於一樣一個整數類型 分紅int Interger兩個類型感受很不必
c#的int是繼承Object的 在須要調用虛函數的時候會自動裝箱
int a = 233; a.ToString()
在jvm上跑的Kotlin 它有一套特殊映射法則 把Int根據狀況自動變換成int和Integer 而在語言層面上只有一個Int
Int a = 233;
a.toString();
可是到了java 你只能這樣
int a = 233; new Integer(a).toString();
或者是這樣
int a = 233; ((Integer)a).toString();
END