1. 程式人生 > >JAVA包裝類及其拆箱裝箱及Integer類拆裝箱的細節

JAVA包裝類及其拆箱裝箱及Integer類拆裝箱的細節

在JAVA中,資料型別可分為兩大種,基本資料型別(值型別)和類型別(引用資料型別)。基本型別的資料不是物件,所以對於要將基本資料型別當物件使用的情況,JAVA提供的包裝類。基本型別和包裝類的對應關係如下:

int -- Integer

char -- Character

double -- Double

float -- Float

byte -- Byte

short -- Short

long -- Long

boolean -- Boolean

所謂裝箱,就是把基本型別用他們相對應的引用型別包裝起來,使他們可以具有物件的特質,如我們可以把int型包裝成Integer類的物件,或者把double包裝成Double等等。

所謂拆箱,就是跟裝箱的方向相反,將Integer及Double這樣的引用型別的物件重新簡化為值型別的資料。

J2SE5.0後提供了自動裝箱和拆箱的功能,此功能事實上是編譯器來幫忙,編譯器在編譯時依照編寫的方法,決定是否進行裝箱或拆箱動作。

自動裝箱的過程:每當需要一種型別的物件時,這種基本來興就自動的封裝到與它相同型別的包裝中。

自動拆箱的過程:每當需要一個值時,被裝箱物件中的值就被自動的提取出來,沒必要再去呼叫intValue()和doubleValue()方法。

自動裝箱只需將該值賦給一個型別包裝器引用,java會自動建立一個物件。例如:

Integer i = 100;//沒有通過new建立,java自動完成

自動拆箱只需將該物件值賦給一個基本型別即可。例如:
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這個Object,因此“==”比較的是其引用。按照常規思維,1和3都應該輸出false,但結果是:

true

true

false

true

結果2和4,是因為ac進行了自動拆箱,因此其比較是基本資料型別的比較,就跟int比較是一樣,“==”在這裡比較的是他們的值,而不是引用。對於結果1,雖然比較的時候還是比較物件的引用,但是自動裝箱時,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) {
			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 static void main(String[] args) {
		Integer m = new Integer(10);
		Integer n = new Integer(10);
		System.out.println(m == n);

		m = m - 1;
		n = n - 1;
		System.out.println(m == n);
	}

輸出結果為:

false

true

原因:m和n都是new出來的物件,記憶體地址不一樣,所以第一次m == n比較的引用不一樣。但是m = m - 1首先進行了自動拆箱m.intValue,相減之後在進行裝箱的動作:m = Integer.valueOf(m.intValue - 1),而m和n都在-128到127之間,所以自動裝箱後,引用的都是快取內的Integer,所以第二次輸出為true.