轉自:java
https://blog.csdn.net/xingkongdeasi/article/details/79618421程序員
部分有所修改:緩存
前言:.net
越是簡單的東西,咱們每每越是沒有去把它明白,但咱們大部分時間又經常在用,就像咱們今天說的int與Integer的使用,咱們程序員基本每天都在用,可是我今天沒用詳細弄清楚以前我也是不清楚,咱們來看看這兩個在用==號比較給咱們帶來的疑問。對象
先看看下面的代碼,看看咱們是否都會blog
@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));
} 內存
答案是:
一、 int1 == int2 -> true
二、 int1 == integer1 -> true
三、 integer1 == integer2 -> false
四、 integer3 == a1 -> false
五、 a1 == a2 -> true
六、 a == b -> false
看看結果跟咱們本身作的是否是都同樣。test
下面咱們就來詳細解釋一下,爲何是上面的結果。(下面的序號就是對應的是上面的答案序號)變量
一、int1 == int2 爲true,這個我就講了,這個都知道程序
二、int1 == integer1,Integer是int的封裝類,當Integer與int進行==比較時,Integer就會拆箱成一個int類型,因此仍是至關於兩個int類型進行比較,這裏的Integer,不論是直接賦值,仍是new建立的對象,只要跟int比較就會拆箱爲int類型,因此就是相等的。
三、integer1 == integer2 -> false,這是兩個都是對象類型,並且不會進行拆箱比較,因此不等
四、integer3 == a1 -> false , integer3是一個對象類型,而a1是一個常量它們存放內存的位置不同,因此也不等,具體存在內存的位置看以看文章:點擊打開連接
五、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種整型