Wrapper包裝類
我們知道Java是一個面相對象的編程語言错沃,基本類型并不具有對象的性質(zhì),為了讓基本類型也具有對象的特征屿岂,就出現(xiàn)了包裝類型(如我們在使用集合類型Collection時就一定要使用包裝類型而非基本類型)携狭,它相當(dāng)于將基本類型“包裝起來”旧找,使得它具有了對象的性質(zhì),并且為其添加了屬性和方法吹艇,豐富了基本類型的操作惰蜜。
另外,當(dāng)需要往ArrayList受神,HashMap中放東西時抛猖,像int,double這種基本類型是放不進(jìn)去的,因為容器都是裝object的财著,這是就需要這些基本類型的包裝器類了联四。
拆箱和裝箱
先看一段代碼:
public static void main(String args[]){
int a = 200;
//普通封裝包裝類型
Integer A1 = new Integer(a);
// 自動裝箱
Integer A2 = a;
Integer B = new Integer(200);
//普通拆箱
int b1 = Integer.valueOf(B);
//自動拆箱
int b2 = B;
}
基本類型和包裝類型的區(qū)別
①基本類型不使用new關(guān)鍵字,他是個常量瓢宦。而包裝類型需要使用new關(guān)鍵字來在堆中分配存儲空間碎连,是個對象;
②基本類型是直接將變量值存儲在棧中(常量在棧中)驮履,而包裝類型是將對象放在堆中(對象在堆中)鱼辙,然后通過引用來使用;
③基本類型的初始值如int為0玫镐,boolean為false倒戏,而包裝類型的初始值為null;
④基本類型使用比較廣泛恐似,包裝類型一般用在ArrayList杜跷,HashMap中。
面試中的常見坑
1.這段代碼的輸出
public static void main(String args[]){
int a1 = 300;
int a2 = 300;
Integer A1 = new Integer(300);
Integer A2 = new Integer(300);
Integer C1 = 3;
Integer D1 = 3;
Integer C2 = 300;
Integer D2 = 300;
System.out.println(a1 == a2);//true
System.out.println(A1 == A2);//false
System.out.println(C1 == D1);//true
System.out.println(C2 == D2);//false
System.out.println(a1 == A1);//true
System.out.println(A1 == C2);//false
System.out.println(a1 == C2);//true
}
下面我們逐一分析結(jié)果
①System.out.println(a1 == a2);//true
因為都是int型矫夷,是基本數(shù)據(jù)類型葛闷,所以==在比較基本數(shù)據(jù)類型的時候,只比較數(shù)值双藕。
②System.out.println(A1 == A2);//false
因為A1淑趾,A2都是new的對象,所以都是在堆中開辟了新的空間的忧陪,==在比較對象的時候扣泊,比較的是引用中存儲的地址,所以是false嘶摊。
③System.out.println(C1 == D1);//true
System.out.println(C2 == D2);//false
這兩個合起來看延蟹,這是咋地啦?怎么換個數(shù)結(jié)果就不一樣了叶堆?
下面這段代碼是Integer的valueOf方法的具體實現(xiàn):
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
而其中IntegerCache類的實現(xiàn)為:
private static class IntegerCache {
static final int high;
static final Integer cache[];
static {
final int low = -128;
// high value may be configured by property
int h = 127;
if (integerCacheHighPropValue != null) {
// Use Long.decode here to avoid invoking methods that
// require Integer's autoboxing cache to be initialized
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}
從上面2段代碼可以看出阱飘,在通過valueOf方法創(chuàng)建Integer對象的時候,如果數(shù)值在[-128,127]之間蹂空,便返回指向IntegerCache.cache中已經(jīng)存在的對象的引用俯萌;否則創(chuàng)建一個新的Integer對象。
④ System.out.println(a1 == A1);//true
System.out.println(A1 == C2);//false
System.out.println(a1 == C2);//true
先分別說一下a1是基本數(shù)據(jù)類型上枕,A1是普通的裝箱的對象咐熙,C2是自動裝箱的對象。
a1==A1:是基本數(shù)據(jù)類型==普通封裝的對象辨萍,這個時候包裝類對象會自動拆箱棋恼,然后比較數(shù)值返弹。
A1 == C2: 自動裝箱也是new了個對象,所以他倆內(nèi)存中地址是不一樣的爪飘。
a1 == C2:和a1==A1同理义起。
2.下面代碼的結(jié)果
public static void main(String args[]){
double a1 = 100.0;
double a2 = 100.0;
Double B1 = 100.0;
Double B2 = 100.0;
Double C1 = 200.0;
Double C2 = 200.0;
System.out.println(a1 == a2);//true
System.out.println(a1 == B1);//true
System.out.println(B1 == B2);//false
System.out.println(C1 == C2);//false
}
①前面兩個
System.out.println(a1 == a2);//true
System.out.println(a1 == B1);//true
老生常談了哈,就是基本數(shù)據(jù)類型之間==比較值师崎,封裝類型和基本數(shù)據(jù)類型==時默终,封裝類型自動拆箱了,所以都是true犁罩!
②后面兩個
System.out.println(B1 == B2);//false
System.out.println(C1 == C2);//false
怎么和int不一樣了齐蔽,沒有緩存了嗎?是的床估,沒有含滴!
public static Double valueOf(double d) {
return new Double(d);
}
源碼里直接,給new了個對象丐巫,這個糟老頭子壞得很谈况!23333
注意:
Integer、Short递胧、Byte碑韵、Character、Long這幾個類的valueOf方法的實現(xiàn)是類似的缎脾。
Double泼诱、Float的valueOf方法的實現(xiàn)是類似的。
3.下面這段代碼的結(jié)果
public static void main(String[] args) {
Boolean a1 = false;
Boolean a2 = false;
Boolean b1 = true;
Boolean b2 = true;
System.out.println(a1==a2);//true
System.out.println(b1==b2);//true
}
為啥都是true呢赊锚,因為源碼中true和false都被定義了靜態(tài)屬性。
public static final Boolean TRUE = new Boolean(true);
/**
* The <code>Boolean</code> object corresponding to the primitive
* value <code>false</code>.
*/
public static final Boolean FALSE = new Boolean(false);
4.下面代碼的輸出
public static void main(String args[]){
Integer a = 10;
Integer b = 20;
Integer c = 30;
Integer d = 30;
Long g = 30L;
Long h = 20L;
System.out.println(c==(a+b));//true
System.out.println(c.equals(a+b));//true
System.out.println(g==(a+b));//true
System.out.println(g.equals(a+b));//false
System.out.println(g.equals(a+h));//true
}
在分析上面代碼結(jié)果前屉栓,要明白四件事:
①當(dāng) "=="運(yùn)算符的兩個操作數(shù)都是 包裝器類型的引用舷蒲,則是比較指向的是否是同一個對象,就是要看引用友多;
②當(dāng) "=="運(yùn)算符的兩個操作數(shù)其中有一個操作數(shù)是表達(dá)式(即包含算術(shù)運(yùn)算)則比較的是數(shù)值(即會觸發(fā)自動拆箱的過程)牲平。
③對于包裝器類型,equals方法并不會進(jìn)行類型轉(zhuǎn)換域滥。euqals會先比較數(shù)據(jù)類型纵柿,再比較值!
④兩個不同的數(shù)據(jù)類型相加启绰,結(jié)果是高的那個數(shù)據(jù)類型昂儒,比如int+float,返回的是float委可。