轉載自 http://macemers.iteye.com/blog/860631
Java包裝類,Wrapper~由於在java中,數據類型總共可分爲兩大種,基本數據類型(值類型)和類類型(引用數據類型)。基本類型的數據不是對象,所以對於要將數據類型作爲對象來使用的情況,java提供了相對應的包裝類。對於8種數據類型的包裝類分別是:
int—Integer
char—Character
float—Float
double—Double
byte—Byte
short—Short
long—Long
boolean–Boolean
java中除了Float,Double之外,都提供了常量池,但只有數值在-128~127之間纔會使用常量池。
所謂裝箱,就是把基本類型用它們相對應的引用類型包起來,使它們可以具有對象的特質,如我們可以把int型包裝成Integer類的對象,或者把double包裝成Double,等等。
所謂拆箱,就是跟裝箱的方向相反,將Integer及Double這樣的引用類型的對象重新簡化爲值類型的數據
J2SE5.0後提供了自動裝箱與拆箱的功能,此功能事實上是編譯器來幫您的忙,編譯器在編譯時期依您所編寫的方法,決定是否進行裝箱或拆箱動作。
自動裝箱的過程:每當需要一種類型的對象時,這種基本類型就自動地封裝到與它相同類型的包裝中。
自動拆箱的過程:每當需要一個值時,被裝箱對象中的值就被自動地提取出來,沒必要再去調用intValue()和doubleValue()方法。
自動裝箱,只需將該值賦給一個類型包裝器引用,java會自動創建一個對象。例如:
Integer i=100;//沒有通過使用new來顯示建立,java自動完成。
自動拆箱,只需將該對象值賦給一個基本類型即可。例如:int j=i;
int i = 10;
Integer j =new Integer(i); //手動裝箱操作
int k = j.intValue(); //手動拆箱操作
int i = 11;
Integer j = i; //自動裝箱
int k = j //自動拆箱
然而在Integer的自動裝拆箱會有些細節值得注意:
public static void main(String[] args) {
Integer a=100;
Integer b=100;
Integer c=200;
Integer d=200;
System.out.println(a==b); //1
System.out.println(a==100); //2
System.out.println(c==d); //3
System.out.println(c==200); //4
}
在java種,”==”是比較object的reference而不是value,自動裝箱後,abcd都是Integer這個Oject,因此“==”比較的是其引用。按照常規思維,1和3都應該輸出false。但結果是:
true
true
false
true
結果2和4,是因爲ac進行了自動拆箱,因此其比較是基本數據類型的比較,就跟int比較時一樣的,“==”在這裏比較的是它們的值,而不是引用。
對於結果1,雖然比較的時候,還是比較對象的reference,但是自動裝箱時,java在編譯的時候 Integer a = 100; 被翻譯成-> Integer a = Integer.valueOf(100);
關鍵就在於這個valueOf()的方法。
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
private static class IntegerCache {
private IntegerCache(){}
static final Integer cache[] = new Integer[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache = new Integer(i - 128);
}
}
根據上面的jdk源碼,java爲了提高效率,IntegerCache類中有一個數組緩存了值從-128到127的Integer對象。當我們調用Integer.valueOf(int i)的時候,如果i的值是>=-128且<=127時,會直接從這個緩存中返回一個對象,否則就new一個Integer對象。
public class TestWhile{ //1
public static void main(String[] args)//2
{
Integer i=0;//3
Integer j=0;//4
// Integer i=new Integer(0);//5
// Integer j=new Integer(0);//6
while(i<=j & i>=j & i!=j)//7
{ //8
System.out.println("0000");//9
}
}
}
那一行是拆箱?while循環裏的條件看似不成立,可爲什麼可以運行(去掉第5、6行的註釋後)?
解答:
這種情況下,循環不能運行。
對於Integer類型,<,<=,>,>=操作將導致拆箱操作,也就是調用Integer的intValue()方法得到相應的基本類型值,然後比較。
但是,==,!=比較的,是對象的引用(Reference)。
Integer i = 0;//3
Integer j = 0;//4
這兩句使用裝箱操作,也就是調用Integer.valueOf(int i);注意,不是使用new。
由於0在 -128–127之間,根據上述,i和j引用的是同一個對象。
綜上,i<=j & i>=j & i!=j中,
i<=j 和 i>=j都成立,而i!=j不成立,因爲i和j引用的是同一個對象。
故此,循環不會執行。
註釋掉3,4兩句,使用5,6兩句時,i和j引用的不是同一個對象,所以i!=j成立。i<=j & i>=j & i!=j成立,循環條件總是成立的,while (i <= j & i >= j & i != j)成爲無窮循環,不斷輸出。
總結,對於要比較Object的值,最穩妥的方法還是調用equals()這個方法(比較的是數值,或者用compareTo(包裝類),返回0時,說明相等),而不是使用==,因此會比較其引用。