包裝類
基本類型 | 大小 | 包裝器類型 |
---|---|---|
byte | 8bit | Byte |
short | 16bit | Short |
int | 32bit | Integer |
long | 64bit | Long |
float | 32bit | Float |
double | 64bit | Double |
boolean | / | Boolean |
char | 16bit | Character |
void | / | Void |
其中绝编,前 6 個(gè)類派生于公共的超類 Number。對(duì)象包裝器類是不可變的貌踏,即一旦構(gòu)造了包裝器十饥,就不允許更改包裝在其中的值。同時(shí)祖乳,對(duì)象包裝器類還是 final逗堵,因此不能定義它們的子類
Java 中的包裝器類有兩個(gè)主要的目的:
提供一種機(jī)制,將基本值“包裝”到對(duì)象中眷昆,從而使基本值能夠包含在為對(duì)象而保留的操作中蜒秤,比如添加到 Collections 中,或者從帶對(duì)象返回值的方法中返回亚斋。注意垦藏,Java 5 增加了自動(dòng)裝箱和拆箱,程序員過(guò)去需手工執(zhí)行的許多包裝操作伞访,現(xiàn)在可以由 Java 自動(dòng)處理了
為基本值提供分類功能掂骏。這些功能大多數(shù)于各種轉(zhuǎn)換有關(guān):在基本值和 String 對(duì)象間相互轉(zhuǎn)換,在基本值和 String 對(duì)象之間按不同基數(shù)轉(zhuǎn)換厚掷,如二進(jìn)制弟灼、八進(jìn)制和十六進(jìn)制
類型互轉(zhuǎn)
裝箱和拆箱
裝箱就是自動(dòng)將基本數(shù)據(jù)類型轉(zhuǎn)換為包裝器類型级解;拆箱就是自動(dòng)將包裝器類型轉(zhuǎn)換為基本數(shù)據(jù)類型:
public static void main(String[] args){
Integer i = 10; //裝箱
int index = i; //拆箱
}
反編譯 class 文件之后可以看到:
編譯器在生成類的字節(jié)碼時(shí),插入了必要的方法調(diào)用田绑,而虛擬機(jī)只是執(zhí)行這些字節(jié)碼勤哗。說(shuō)明裝箱和拆箱是編譯器認(rèn)可的,而不是虛擬機(jī)掩驱。
裝箱過(guò)程是通過(guò)調(diào)用包裝器的 valueOf 方法實(shí)現(xiàn)的芒划,而拆箱過(guò)程是通過(guò)調(diào)用包裝器的 xxxValue 方法實(shí)現(xiàn)的。(xxx 代表對(duì)應(yīng)的基本數(shù)據(jù)類型)
注意欧穴,如果在一個(gè)表達(dá)式中混合使用 Integer 和 Double 類型民逼,Integer 值就會(huì)拆箱,提升為 double涮帘,再裝箱為 Double:
Integer n = 1;
Double x = 2.0;
System.out.println(true ? n : x); // 1.0
相關(guān)問(wèn)題
- 下面這段代碼的輸出結(jié)果是什么拼苍?
public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1 == i2);
System.out.println(i3 == i4);
}
}
結(jié)果:
true
false
這里注意 “== ”和 “equal” 的區(qū)別:
基本類型 | == | equals |
---|---|---|
字符串變量 | 對(duì)象在內(nèi)存中的首地址 | 字符串內(nèi)容 |
非字符串變量 | 對(duì)象在內(nèi)存中的首地址 | 對(duì)象在內(nèi)存中的首地址 |
基本類型 | 值 | 不可用 |
包裝類 | 地址 | 內(nèi)容 |
輸出結(jié)果表明 i1 和 i2 指向的是同一個(gè)對(duì)象,而 i3 和 i4 指向的是不同的對(duì)象调缨。此時(shí)只需一看源碼便知究竟疮鲫,下面這段代碼是 Integer 的 valueOf 方法的具體實(shí)現(xiàn):
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
可以看出,在通過(guò) valueOf 方法創(chuàng)建 Integer 對(duì)象的時(shí)候弦叶,如果數(shù)值在 [-128,127] 之間俊犯,便返回指向 IntegerCache.cache 中已經(jīng)存在的對(duì)象的引用;否則創(chuàng)建一個(gè)新的 Integer 對(duì)象
IntegerCache 源碼:
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
IntegerCache 是一個(gè)工具類伤哺,初始化了 cache燕侠,并將構(gòu)造方法聲明為 private,禁止外部創(chuàng)建
上面的代碼中 i1 和 i2 的數(shù)值為 100默责,因此會(huì)直接從 cache 中取已經(jīng)存在的對(duì)象贬循,所以 i1 和 i2 指向的是同一個(gè)對(duì)象,而 i3 和 i4 則是分別指向不同的對(duì)象
- 下面這段代碼的輸出結(jié)果是什么桃序?
public class Main {
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1 == i2);
System.out.println(i3 == i4);
}
}
結(jié)果:
false
false
在某個(gè)范圍內(nèi)的整型數(shù)值的個(gè)數(shù)是有限的杖虾,而浮點(diǎn)數(shù)卻不是。所以 Double 類型沒(méi)有緩存
注意媒熊,Integer奇适、Short、Byte芦鳍、Character嚷往、Long 這幾個(gè)類的 valueOf 方法的實(shí)現(xiàn)是類似的,Double柠衅、Float 的 valueOf 方法的實(shí)現(xiàn)是類似的
- 下面這段代碼的輸出結(jié)果是什么皮仁?
public class Main {
public static void main(String[] args) {
Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
結(jié)果為:
true
true
至于為什么是這個(gè)結(jié)果,看了 Boolean 類的源碼也會(huì)一目了然:
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
public static final Boolean TRUE = new Boolean(true);
/**
* The {@code Boolean} object corresponding to the primitive
* value {@code false}.
*/
public static final Boolean FALSE = new Boolean(false);
- 下面這段代碼的輸出結(jié)果是什么?
public class Main {
public static void main(String[] args) {
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 == (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));
}
}
注意:當(dāng) “==” 運(yùn)算符的兩個(gè)操作數(shù)都是包裝器類型的引用贷祈,則是比較指向的是否是同一個(gè)對(duì)象趋急,而如果其中有一個(gè)操作數(shù)是表達(dá)式(即包含算術(shù)運(yùn)算)則比較的是數(shù)值(即會(huì)觸發(fā)自動(dòng)拆箱的過(guò)程)。另外势誊,對(duì)于包裝器類型呜达,equals 方法并不會(huì)進(jìn)行類型轉(zhuǎn)換。下面是 Integer 的 equals 方法:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
結(jié)果:
true
true
true
false
true
第一句由于 a+b 包含了算術(shù)運(yùn)算粟耻,因此會(huì)觸發(fā)自動(dòng)拆箱過(guò)程(會(huì)調(diào)用 intValue 方法)查近,因此它們比較的是數(shù)值是否相等。
而對(duì)于 c.equals(a+b) 會(huì)先觸發(fā)自動(dòng)拆箱過(guò)程挤忙,再觸發(fā)自動(dòng)裝箱過(guò)程霜威,也就是說(shuō) a+b,會(huì)先各自調(diào)用intValue方法饭玲,得到了加法運(yùn)算后的數(shù)值之后侥祭,便調(diào)用 Integer.valueOf 方法叁执,再進(jìn)行 equals 比較茄厘。
同理對(duì)于后面的也是這樣,不過(guò)要注意倒數(shù)第二個(gè)和最后一個(gè)輸出的結(jié)果(如果數(shù)值是 int 類型的谈宛,裝箱過(guò)程調(diào)用的是 Integer.valueOf次哈;如果是 long 類型的邀跃,裝箱調(diào)用的 Long.valueOf 方法)