转载请注明出处: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