Java Integer於Int 進行==雙等於的記憶體比較時的一些問題說明
轉自:
https://blog.csdn.net/xingkongdeasi/article/details/79618421
部分有所修改:
前言:
越是簡單的東西,我們往往越是沒有去把它明白,但我們大部分時間又常常在用,就像我們今天說的int與Integer的使用,我們程式設計師基本天天都在用,但是我今天沒用詳細弄清楚之前我也是不清楚,我們來看看這兩個在用==號比較給我們帶來的疑問。
先看看下面的程式碼,看看我們是否都會
@Test
public void testEquals() {
int int1 = 12;
int int2 = 12;
Integer integer1 = new Integer(12);
Integer integer2 = new Integer(12);
Integer integer3 = new Integer(127);
Integer a1 = 127;
Integer a2 = 127;
Integer a = 128;
Integer b = 128;
System.out.println("int1 == int2 -> " + (int1 == int2));
System.out.println("int1 == integer1 -> " + (int1 == integer1));
System.out.println("integer1 == integer2 -> " + (integer1 == integer2));
System.out.println("integer3 == a1 -> " + (integer3 == a1));
System.out.println("a1 == a2 -> " + (a1 == a2));
System.out.println("a == b -> " + (a == b));
}
答案是:
1、 int1 == int2 -> true
2、 int1 == integer1 -> true
3、 integer1 == integer2 -> false
4、 integer3 == a1 -> false
5、 a1 == a2 -> true
6、 a == b -> false
看看結果跟我們自己做的是不是都一樣。
下面我們就來詳細解釋一下,為什麼是上面的結果。(下面的序號就是對應的是上面的答案序號)
1、int1 == int2 為true,這個我就講了,這個都知道
2、int1 == integer1,Integer是int的封裝類,當Integer與int進行==比較時,Integer就會拆箱成一個int型別,所以還是相當於兩個int型別進行比較,這裡的Integer,不管是直接賦值,還是new建立的物件,只要跟int比較就會拆箱為int型別,所以就是相等的。
3、integer1 == integer2 -> false,這是兩個都是物件型別,而且不會進行拆箱比較,所以不等
4、integer3 == a1 -> false , integer3是一個物件型別,而a1是一個常量它們存放記憶體的位置不一樣,所以也不等,具體存在記憶體的位置看以看文章:點選開啟連結
5、6 看起來是一模一樣的為什麼一個是true,一個是false,這是因為Integer作為常量時,對於-128到127之間的數,會進行快取,也就是說int a1 = 127時,在範圍之內,這個時候就存放在快取中,當再建立a2時,java發現快取中存在127這個數了,就直接取出來賦值給a2,所以a1 == a2的。當超過範圍就是new Integer()來new一個物件了,所以a、b都是new Integer(128)出來的變數,所以它們不等。
根據以上總結:
①、無論如何,Integer與new Integer不會相等。不會經歷拆箱過程,因為它們存放記憶體的位置不一樣。(要看具體位置,可以看看這篇文章:點選開啟連結)
(Arnold備註:new Integer()必然是堆記憶體中新增資料,Integer 是java的常亮實現類,如果是在-128到127時則存在於常量池中,如果大於127,則在堆記憶體中新增物件,==比較的為記憶體地址,所以即使
new Integer() 和直接使用Integer 定義資料,都是在堆記憶體中儲存的資料,則對應的記憶體地址也不會相同,所以,new Integer 於 Integer 必然不會相等)
②、兩個都是非new出來的Integer,如果數在-128到127之間,則是true,否則為false。
③、兩個都是new出來的,則為false。(備註:除了進入常量池的物件,在例項化前會去常量池中比較是否有相同的內容,相同則返回當前常量池的記憶體地址,其餘進入堆記憶體空間的物件,一律是直接開闢空間進行堆記憶體的儲存,不會進行是否已經存在的判斷)
④、int和integer(new或非new)比較,都為true,因為會把Integer自動拆箱為int,其實就是相當於兩個int型別比較。(備註:兩個int 的比較操作,實際就是直接進行值的比較的操作)
(Arnold備註:方法區常量池的概念此處不再贅述,此處主要說明下,java中常量池對基本型別的一些實現:)
Java中實現常量池的基本型別的包裝類分別是:String,Byte,Short,Integer,Long,Character,Boolean,浮點數的包裝型別則沒有實現,Byte,Short,Integer,Long,Character 五中型別
也只是在對應的值小於 127和-128時才會實現常量池,超出該值的範圍則直接在堆內建立記憶體,於上述介紹的Integer的常量池一致,而對於String的常量池則和上面所提到的其他型別的常量池基本一致,
對於直接String =“”“” 來建立的物件資料則是直接儲存在常量池中,沒有大小和範圍的限制,而對於直接 使用 new 的方式建立的物件,則都會直接放到堆記憶體中,此處於其餘的常量池的實現類是一致的。
可參考如下連結:https://blog.csdn.net/qiaoijun/article/details/48878039
String s = "Java" 這種宣告的方式。產生的這種"常量"就會被放到常量池,常量池是JVM的一塊特殊的記憶體空間。
使用Java常量池技術,是為了方便快捷地建立某些物件,當你需要一個物件時候,就去這個池子裡面找,找不到就在池子裡面建立一個。但是必須注意 如果物件是用new 建立的。那麼不管是什麼對像,它是不會放到池子裡的,而是向堆申請新的空間儲存。
java中基本型別的包裝類的大部分都實現了常量池技術,這些類是Byte,Short,Integer,Long,Character,Boolean,另外兩種浮點數型別的包裝類則沒有實現。另外Byte,Short,Integer,Long,Character這5種整型