先看代碼:
int i1 = 128;
Integer i2 = 128;
Integer i3 = new Integer(128);
//Integer會自動拆箱為int,所以為true
System.out.println(i1 == i2);
System.out.println(i1 == i3);
System.out.println(i2 == i3);
System.out.println("**************");
Integer i4 = 127;//java在編譯的時(shí)候,被翻譯成-> Integer i5 = Integer.valueOf(127);
Integer i5 = 127;
Integer i6 = Integer.valueOf(127);
System.out.println(i4 == i5);//true
System.out.println(i4 == i6);//true
Integer i7 = new Integer(127);
System.out.println(i4 == i7); //false
Integer i8 = 128;
Integer i9 = 128;
System.out.println(i8 == i9);//false
Integer i10 = new Integer(128);
Integer i11 = new Integer(128);
System.out.println(i10 == i11); //false
測試的結(jié)果:

在Java中,對于對象==是比較兩個(gè)對象的地址。
Integer的存儲
1、Integer是int的封裝類,當(dāng)基礎(chǔ)變量(int)和Integer進(jìn)行比較時(shí),Integer會自動拆箱(jdk1.5以上)了后,再去和int進(jìn)行比較,所以判斷i1==i2,i1==i3都為true。
2、對JVM為了節(jié)省空間, 當(dāng)Integer的值落在-128~127之間時(shí),如i4,i5;此時(shí)JVM首先檢查是否已存在值為127的Integer對象。如果是,則i4,i5直接是引用已存在對象,即i4 = i5。所以判斷i4 == i5 為 true
那為什么范圍是-128到127呢:java在編譯Integer i4 = 127的時(shí)候,是被翻譯成-> Integer i4 = Integer.valueOf(127)的;這就是判斷i4==i6為true的原因了。接下來,關(guān)鍵就是看valueOf()函數(shù)了。只要看看valueOf()函數(shù)的源碼就會明白了。


從代碼上看出, 當(dāng)要賦的值在[-128~127]范圍內(nèi),則會直接指向該值的引用,不用去new 個(gè)對象到堆內(nèi)存中去了。因?yàn)镮nteger已經(jīng)緩存了數(shù)據(jù)。但是,當(dāng)超出了數(shù)組的范圍值時(shí),就會去自動裝箱在堆內(nèi)存中建一個(gè)新對象。所以,對i8,i9,即使基礎(chǔ)變量值一樣,封裝類對象卻指向不同地址。所以判斷i8==i9為false
3、對于顯式的new Integer(int i),JVM將直接分配新空間。這樣兩個(gè)new Integer(int i)分配的堆內(nèi)存空間肯定不是同一個(gè),所以判斷i10== i11為false。
此外兩點(diǎn), 顯式的new Integer(int i)和int自動裝箱成的Integer,并不會是同一個(gè)對象。他們也是兩個(gè)不同的存在堆內(nèi)存中的空間。所以判斷i2==i3為false;顯式的new Integer(int i)和i范圍在[-128~127]內(nèi)的直接賦值Int類型的值也不指向同一個(gè)空間。如判斷i4==i7為false,i7指向常量池,而i4指向的是堆內(nèi)存。
接下來是我的另一個(gè)思考:Integer作為對象包裝器類,是沒有set()方法的。他的值是final的。

那我就是想給他改值怎么辦。可以!用反射。
Integer j1 = 2;
Integer j2 = 2;
System.out.println("j1 = j2? " + (j1 == j2)); //true
try {
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
field.set(j2,129);
System.out.println( "j1+"+j1+"+j2+" + j2
+"\nSystem.identityHashCode(j1)"+System.identityHashCode(j1)
+"\nSystem.identityHashCode(j2)"+System.identityHashCode(j2)
+"\nj1 == j2" + (j1 == j2));
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Integer j3 = 2;
Integer j4 = 2;
System.out.println("j3+"+j3+"\nSystem.identityHashCode(j3)"+System.identityHashCode(j3)+"\nj3 = j4? " + (j3 == j4));
輸出結(jié)果:

我們可以看出什么呢?常量池里的對應(yīng)值改變了,所有調(diào)用2的值返回的都是129。這是為什么,我畫了個(gè)圖,請看:

當(dāng)我通過反射修改值時(shí),改變了就是常量池中,IntegerCache.cache[]數(shù)組中的值。而我們的下標(biāo)并沒有改變。(這里可能會有人說我常量池與IntegerCache.cache[]數(shù)組之間理解有問題,我還沒深入研究過,只是想表示是以數(shù)組方式存儲的)
所以第三步我們所謂的賦值“=”,對應(yīng)的是常量池中2對應(yīng)的下標(biāo)里的值,改成了129。
就好比:int[10] i = {0,1,2,3
,9} 變成了int[10] i = {0,1,129,3,9} 。因此上面的輸出結(jié)果沒問題,所有對應(yīng)的Integer里,本來是2的值都變成了129。所以?。?!沒事別像我一樣瞎想。
String的存儲
對于使用字面量賦值方式。JVM為了節(jié)省空間,會首先查找JVM中是否有對應(yīng)的字符串常量。如果已經(jīng)存在,則直接返回該引用,而無需重新創(chuàng)建對象。對象new創(chuàng)建方式,JVM將分配新空間。
String a="1";
String b="1";
int aHashCode = System.identityHashCode(a);
int bHashCode = System.identityHashCode(b);
System.out.print("\na:"+a+"\nb:"+b);
System.out.print("\naHashCode:"+aHashCode+"\nbHashCode:"+bHashCode);
try {
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
char[] valueChar = (char[]) value.get(b);
valueChar[0] = '2';
String c="1";
String d="2";
int cHashCode = System.identityHashCode(c);
int dHashCode = System.identityHashCode(d);
System.out.print("\na:"+a+"\nb:"+b+"\nc:"+c+"\nd:"+d);
System.out.print("\naHashCode:"+aHashCode+"\nbHashCode:"+bHashCode+"\ncHashCode:"+cHashCode+"\ndHashCode:"+dHashCode);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
對應(yīng)的輸出:

一個(gè)例子,來自:http://blog.csdn.net/hejingyuan6/article/details/50489171:
String s1 = "china";
String s2 = "china";
String ss1 = new String("china");
String ss2 = new String("china");
int i = 1;
int j = 1;
public static final int i1 = 1;
public static final int j1 = 1;
Integer it1 = 127;
Integer it2 = 127;
Integer it11 = 128;
Integer it12 = 128;
還有一點(diǎn),就是String的拼接,作用于哪要看虛擬機(jī)和編譯的jdk版本。我沒深入研究,你們看著辦吧。反正,對于頻繁長拼接,用StringBuffer更好。
最后附上整個(gè)class的測試代碼:
package com.yy007.zxing;
import java.lang.reflect.Field;
/**
* Created by 仁昌居士 on 2017/6/16.
* Description:
*/
public class TestAcitivity {
/**
* @param args
*/
public static void main(String[] args) {
int i1 = 128;
Integer i2 = 128;
Integer i3 = new Integer(128);
//Integer會自動拆箱為int,所以為true
System.out.println(i1 == i2);
System.out.println(i1 == i3);
System.out.println(i2 == i3);
System.out.println("**************");
Integer i4 = 127;//java在編譯的時(shí)候,被翻譯成-> Integer i5 = Integer.valueOf(127);
Integer i5 = 127;
Integer i6 = Integer.valueOf(127);
System.out.println(i4 == i5);//true
System.out.println(i4 == i6);//true
Integer i7 = new Integer(127);
System.out.println(i4 == i7); //false
Integer i8 = 128;
Integer i9 = 128;
System.out.println(i8 == i9);//false
Integer i10 = new Integer(128);
Integer i11 = new Integer(128);
System.out.println(i10 == i11); //false
System.out.println("**************");
Integer j1 = 2;
Integer j2 = 2;
System.out.println("j1 = j2? " + (j1 == j2)); //true
try {
Field field = Integer.class.getDeclaredField("value");
field.setAccessible(true);
field.set(j2,129);
System.out.println( "j1+"+j1+"+j2+" + j2
+"\nSystem.identityHashCode(j1)"+System.identityHashCode(j1)
+"\nSystem.identityHashCode(j2)"+System.identityHashCode(j2)
+"\nj1 == j2" + (j1 == j2));
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Integer j3 = 2;
Integer j4 = 2;
System.out.println("j3+"+j3+"\nSystem.identityHashCode(j3)"+System.identityHashCode(j3)+"\nj3 = j4? " + (j3 == j4));
System.out.println("**************");
String a="1";
String b="1";
int aHashCode = System.identityHashCode(a);
int bHashCode = System.identityHashCode(b);
System.out.print("\na:"+a+"\nb:"+b);
System.out.print("\naHashCode:"+aHashCode+"\nbHashCode:"+bHashCode);
try {
Field value = String.class.getDeclaredField("value");
value.setAccessible(true);
char[] valueChar = (char[]) value.get(b);
valueChar[0] = '2';
String c="1";
String d="2";
int cHashCode = System.identityHashCode(c);
int dHashCode = System.identityHashCode(d);
System.out.print("\na:"+a+"\nb:"+b+"\nc:"+c+"\nd:"+d);
System.out.print("\naHashCode:"+aHashCode+"\nbHashCode:"+bHashCode+"\ncHashCode:"+cHashCode+"\ndHashCode:"+dHashCode);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}