今天看到這樣一道題;
class AutoUnboxingTest {
public static void main(String[] args) {
Integer a = new Integer(3);
Integer b = 3; // 将3自動裝箱成Integer類型
int c = 3;
System.out.println(a == b); // false 兩個引用沒有引用同一對象
System.out.println(a == c); // true a自動拆箱成int類型再和c比較
}
}
從jdk5開始引入了裝箱、拆箱機制,關于Integer中的==,jdk源代碼是這樣寫的:
* @since 1.5
*/
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
上面這段代碼首先規定了一個範圍,預設是-128-127之間,如果參數中的i在這個範圍之内,則傳回一個數組中的内容,如果不在這個範圍,則new一個新的Integer對象并傳回。檢視Integer類的源碼可以發現,這個數組裡面緩存了基本類型-128-127之間的Integer對象。顯然:Integerb=3 是将3自動轉型了,而a是直接new了一個對象,開辟了一塊新的堆空間,是以他們的指向位址肯定是不相等的。
在Integer常量池中,Integer隻對包裝了int值在-128-127這個範圍的Integer對象做了共享。這種共享模式叫做享元模式,在所有設計模式中都有各自的優點和缺點,享元模式也不例外。享元模式它的優點在于,通過共享一些對象降低記憶體中相同對象的數量。
但是,想象一下int類型從0x80000000到0x7fffffff如果把所有這些數字包裝成共享對象,那需要的對象的數量将是多麼的龐大,恐怕還不如不進行處理呢,另外在程式中有很多用不上(在項目中從來那沒見那個程式會把所有的int值用個遍的)。
是以Integer隻對包裝了int值在-128-127這個範圍的Integer對象做了共享。如果超過了這個範圍,就會在堆空間上開辟一個新的區域(return new Integer(i);)
再來一道題:
public static void main(String[] args) {
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2);
System.out.println(f3 == f4);
}
f1==f2,這裡會給f2自動裝箱,因為是在-128-127之間,是以不用new新的對象了,直接引用常量池的對象。故他們指向的是同一個對象,是true; f3==f4,f3 f4不在-128-127之間,是以各自在堆中開辟新的空間,指向的不是同一對象,為false。
總結 Object類中的equals方法和“==”是一樣的,沒有差別,而String類,Integer類等等一些類,是重寫了equals方法,才使得equals和“==不同”,“==比較位址,equals比較值”。 但是對于包裝類和基本類型,還要涉及它們的自動裝箱、自動拆箱,是以小心一點還是比較好的,不要走到别人挖的陷阱中。