轉載請註明出處:http://blog.csdn.net/infant09/article/details/77822913
關鍵詞:java; String; 字面量; 顯式; 聲明; 對象; 顯示; 直接聲明; 直接定義
String對象的幾種創建方式
String類是Java中比較特殊的一類。Java在設計時爲了提高String類的使用效率,使用String Pool的機制進行String管理。
String對象有以下幾種聲明方式:
顯式聲明(使用字面量創建對象,String literals):
String s = "abc";
new關鍵字聲明:
//通過String創建新的String對象,此方法是redundant String s0 = new String("123"); //通過char數組來生成String char c[] = {48, 49}; String s1 = new String(c); //通過int來生成String int i = 123; String s2 = String.valueOf(i); //other function ......
字符串拼接(使用字面量創建對象):
String s = "123" + "456";
問題提出
通過new關鍵字聲明,實際上是調用了String類的構造方法。但是通過雙引號進行顯式聲明,是如何創建對象的呢?
Java的基本類型,可以直接顯式聲明,但是String不是基本類型,顯然是編譯器隱藏了一些細節。
問題解決
String源碼
通過閱讀String類的源碼,可以發現這樣一段話:
* <blockquote><pre>
* String str = "abc";
* </pre></blockquote><p>
* is equivalent to:
* <blockquote><pre>
* char data[] = {'a', 'b', 'c'};
* String str = new String(data);
* </pre></blockquote><p>
因此我們可以得知,當使用String str = "abc"
聲明時,等價於首先創建了char數組,然後調用new String的構造方法。
當然,這只是“等價於”(equivalent),編譯器做了一些處理。顯式調用String str = "abc"
和調用char data[] = {'a', 'b', 'c'}; String str = new String(data);
是不一樣的過程。
bytecode理解
顯式調用
package Test; public class StringTest { public static void main(String[] args) { String s = "abc"; } }
使用
$ javap -c StringTest.class
查看編譯後的class文件:public class Test.StringTest { public Test.StringTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: ldc #2 // String abc 2: astore_1 3: return }
根據字符串池(String Pool)的機制,
String str = "abc"
會先在常量池裏的字符串池查找"abc"
對象,如果沒有則創建;然後在棧(stack)中創建str引用,直接指向String pool中的"abc"
對象。new關鍵字聲明
package Test; public class StringTest { public static void main(String[] args) { char c[] = {'a', 'b', 'c'}; String s = new String(c); } }
字節碼如下:
public class Test.StringTest { public Test.StringTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: iconst_3 1: newarray char 3: dup 4: iconst_0 5: bipush 97 7: castore 8: dup 9: iconst_1 10: bipush 98 12: castore 13: dup 14: iconst_2 15: bipush 99 17: castore 18: astore_1 19: new #2 // class java/lang/String 22: dup 23: aload_1 24: invokespecial #3 // Method java/lang/String."<init>":([C)V 27: astore_2 28: return }
可以首先在堆(heap)中創建對象,然後調用String類的構造方法。當然,調用構造方法的過程中,會在String pool裏查找或創建
"abc"
對象,然後再根據這個對象去heap中創建對象。
這就是顯式聲明字符串的過程。
其他問題
- 字符串常量池究竟在JVM的哪裏?
- String s = new String(“abc”) + “abc”,創建了多少個對象?以及其他類似問題
參考文獻
https://tech.meituan.com/in_depth_understanding_string_intern.html