1、基本概念
字節的單位:byte。位的單位:bit,1byte=8bit
2、8種基本數據類型
4種整型,2種浮點類型,1種用於表示Unicode編碼的字符單元的字符類型和1種用於表示真值的boolean類型。
數據類型 | 浮點型大小(占字節數,2的幾次方) | 范圍 | 默認值 | 包裝器類型 |
byte(字節) | 8 | -128 - 127 | 0 | Byte |
shot(短整型) | 16 | -32768 - 32768 | 0 | Short |
int(整型) | 32 | -2147483648-2147483648 | 0 | Integer |
long(長整型) | 64 | -9233372036854477808-9233372036854477808 | 0 | Long |
float(浮點型) | 32 | -3.40292347E+38-3.40292347E+38 | 0.0f | Float |
double(雙精度) | 64 | -1.79769313486231570E+308-1.79769313486231570E+308 | 0.0d | Double |
char(字符型) | 16 | ‘ \u0000 - u\ffff ’ | ‘\u0000 ’ | Character |
boolean(布爾型) | 1 | true/false | false | Boolean |
3、包裝類
包裝類即使把基本類型變成對象類型,包含每種基本數據類型的相關屬性如最大值、最小值等,以及相關的操作方法。
4、包裝類轉換關系
基本類型 --> 包裝器類
Integer obj=new Integer(10);
包裝器類 --> 基本類型
int num=obj.intValue();
字符串 --> 包裝器類
Integer obj=new Integer("100");
字符串 --> 基本類型
int num=Integer.parseInt("-45.36");
5、自動裝包/拆包(Autoboxing/unboxing)
基本類與包裝類的轉換,則是裝包與拆包
自動裝包/拆包大大方便了基本類型數據和它們包裝類地使用。
自動裝包:基本類型自動轉為包裝類.(int >> Integer)
自動拆包:包裝類自動轉為基本類型.(Integer >> int)
int 是基本類型,直接存儲數值
Integer是對象類,new一個對象時用一個引用指向這個對象
Java把內存划分成兩種:一種是棧內存,另一種是堆內存
在函數中定義的一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配,而實際的對象是在存儲堆內存中
比如
int i = 10; ----直接在棧中分配空間
Integer j = new Integr(5); ----對象是在堆內存中,而j(引用變量)是在棧內存中
在堆中分配的內存,由java虛擬機的自動垃圾回收器來管理。 因為在堆中分配空間所需的時間遠大於從棧中分配存儲空間
一.什么是裝箱?什么是拆箱?
二.裝箱和拆箱是如何實現的
三.面試中相關的問題
一.什么是裝箱?什么是拆箱?
在前面的文章中提到,Java為每種基本數據類型都提供了對應的包裝器類型,至於為什么會為每種基本數據類型提供包裝器類型在此不進行闡述,有興趣的朋友可以查閱相關資料。在Java SE5之前,如果要生成一個數值為10的Integer對象,必須這樣進行:
Integer i =
new
Integer(
10
);
而在從Java SE5開始就提供了自動裝箱的特性,如果要生成一個數值為10的Integer對象,只需要這樣就可以了:
Integer i =
10
;
這個過程中會自動根據數值創建對應的 Integer對象,這就是裝箱。
那什么是拆箱呢?顧名思義,跟裝箱對應,就是自動將包裝器類型轉換為基本數據類型:
Integer i =
10
;
//裝箱
int
n = i;
//拆箱
int(4字節) | Integer |
byte(1字節) | Byte |
short(2字節) | Short |
long(8字節) | Long |
float(4字節) | Float |
double(8字節) | Double |
char(2字節) | Character |
boolean(未定) | Boolean |
public
class
Main {
public
static
void
main(String[] args) {
Integer i =
10
;
int
n = i;
}
}

從反編譯得到的字節碼內容可以看出,在裝箱的時候自動調用的是Integer的valueOf(int)方法。而在拆箱的時候自動調用的是Integer的intValue方法。
其他的也類似,比如Double、Character,不相信的朋友可以自己手動嘗試一下。
因此可以用一句話總結裝箱和拆箱的實現過程:
裝箱過程是通過調用包裝器的valueOf方法實現的,而拆箱過程是通過調用包裝器的 xxxValue方法實現的。(xxx代表對應的基本數據類型)。
三.面試中相關的問題
雖然大多數人對裝箱和拆箱的概念都清楚,但是在面試和筆試中遇到了與裝箱和拆箱的問題卻不一定會答得上來。下面列舉一些常見的與裝箱/拆箱有關的面試題。
1.下面這段代碼的輸出結果是什么?
答案是i1=i2 true;
i3=i4 false;
為什么會出現這樣的結果?輸出結果表明i1和i2指向的是同一個對象,而i3和i4指向的是不同的對象.
只需一看源碼便知究竟,下面這段代碼是Integer的valueOf方法的具體實現.
在通過valueOf方法創建Integer對象的時候,如果數值在[-128,127]之間,便返回指向IntegerCache.cache中已經存在的對象的引用;否則創建一個新的Integer對象。
上面的代碼中i1和i2的數值為100,因此會直接從cache中取已經存在的對象,所以i1和i2指向的是同一個對象,而i3和i4則是分別指向不同的對象。
2.下面這段代碼的輸出結果是什么?
false
false
至於具體為什么,讀者可以去查看Double類的valueOf的實現。
在這里只解釋一下為什么Double類的valueOf方法會采用與Integer類的valueOf方法不同的實現。很簡單:在某個范圍內的整型數值的個數是有限的,而浮點數卻不是。
注意,Integer、Short、Byte、Character、Long這幾個類的valueOf方法的實現是類似的。
Double、Float的valueOf方法的實現是類似的。
Boolean i11 = false;
Boolean i21 = false;
Boolean i31 = true;
Boolean i41 = true;
System.out.println(i11==i21);
System.out.println(i31==i41);
true
true
4.談談Integer i = new Integer(xxx)和Integer i =xxx;這兩種方式的區別。
當然,這個題目屬於比較寬泛類型的。但是要點一定要答上,我總結一下主要有以下這兩點區別:
1)第一種方式不會觸發自動裝箱的過程;而第二種方式會觸發;
2)在執行效率和資源占用上的區別。第二種方式的執行效率和資源占用在一般性情況下要優於第一種情況(注意這並不是絕對的)。
Integer a =
1
;
Integer b =
2
;
Integer c =
3
;
Integer d =
3
;
Integer e =
321
;
Integer f =
321
;
Long g = 3L;
Long h = 2L;
System.out.println(c==d);
System.out.println(e==f);
System.out.println(c==(a+b));
System.out.println(c.equals(a+b));
System.out.println(g==(a+b));
System.out.println(g.equals(a+b));
System.out.println(g.equals(a+h));
true
false
true
true
true
false
true
這里面需要注意的是:當 "=="運算符的兩個操作數都是 包裝器類型的引用,則是比較指向的是否是同一個對象,而如果其中有一個操作數是表達式(即包含算術運算)則比較的是數值(即會觸發自動拆箱的過程)。另外,對於包裝器類型,equals方法並不會進行類型轉換。明白了這2點之后,上面的輸出結果便一目了然。
第一個和第二個輸出結果沒有什么疑問。第三句由於 a+b包含了算術運算,因此會觸發自動拆箱過程(會調用intValue方法),因此它們比較的是數值是否相等。而對於c.equals(a+b)會先觸發自動拆箱過程,再觸發自動裝箱過程,也就是說a+b,會先各自調用intValue方法,得到了加法運算后的數值之后,便調用Integer.valueOf方法,再進行equals比較。同理對於后面的也是這樣,不過要注意倒數第二個和最后一個輸出的結果(如果數值是int類型的,裝箱過程調用的是Integer.valueOf;如果是long類型的,裝箱調用的Long.valueOf方法)。