JAVA String對象的建立,javastring對象
String對象的建立是比較特殊的,普通對象建立都是在堆中建立,String對象確不一定,下面看一段代碼
public class StringTest1 {public static void main(String[] args) throws Exception{String a = "abc";String b = "abc";String c = "ab";String d = new String("ab");System.out.println("a=" + a);//a=abcSystem.out.println("b=" + b);//b=abcSystem.out.println("c=" + c);//c=abSystem.out.println("d=" + d);//d=abSystem.out.println("a==b is " + (a == b));//a==b is trueSystem.out.println("c==d is " + (c == d));//c==d is falseField field = String.class.getDeclaredField("value");field.setAccessible(true);char[] valueA = (char[]) field.get(a);char[] valueB = (char[]) field.get(b);char[] valueC = (char[]) field.get(c);char[] valueD = (char[]) field.get(d);System.out.println("a.value(" + valueA.hashCode() + ")=" + Arrays.toString(valueA));//a.value([1829164700)=[a, b, c]System.out.println("b.value(" + valueB.hashCode() + ")=" + Arrays.toString(valueB));//b.value([1829164700)=[a, b, c]System.out.println("c.value(" + valueC.hashCode() + ")=" + Arrays.toString(valueC));//c.value([2018699554)=[a, b]System.out.println("d.value(" + valueD.hashCode() + ")=" + Arrays.toString(valueD));//d.value([2018699554)=[a, b]valueA[0] = 'z';valueD[0] = 'x';System.out.println("a=" + a);//a=zbcSystem.out.println("b=" + b);//b=zbcSystem.out.println("c=" + c);//c=xbSystem.out.println("d=" + d);//d=xb}}
a跟b都是“abc”,測試結果a跟b的引用是相等的,value數組也是相等的,改變a的第一位,b也跟著變了。
c跟d都是“ab”,但是兩個引用是不相等的,d是用new建立的,這個時候才會在堆中建立對象,a,b,c三個引用都是直接指向常量池的對象的,但是下面c和d的value似乎又是同一個數組,改變d的第一位,c也變了,說明d在堆中建立的對象還是指向常量池的,所以用new的話就多建立了個對象。
還有一個經典的問題, String a = "a" + "b";建立了幾個對象。
一般來說應該是3個吧,一個"a",一個"b",一個結果"ab",下面寫一個簡單的類
public class StringTest2 {@SuppressWarnings("unused")public static void main(String[] args){String a = "a" + "b";}}
使用javap看一下位元組碼
javap -c StringTest2.classCompiled from "StringTest2.java"public class test.StringTest2 { public test.StringTest2(); Code: 0: aload_0 1: invokespecial #8 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #16 // String ab 2: astore_1 3: return}
只有一個指令ldc #16 ,從常量池裡加常量#16,很明顯這個常量就是ab,我就不去解析class檔案了,應該是沒錯,直接反編譯一下,得到的結果是
package test;public class StringTest2{ public static void main(String[] args) { String a = "ab"; }}
所以引用直接指向常量池"ab"了,就一個對象嗎,可能是編譯器最佳化的結果吧,如果有時間去單獨把class檔案一個位元組一個位元組解析出來結果應該更明了。