Java中的字符串只能位于内存中的两个区域:常量池和Java堆。常量池维护了一个StringTable,它是一个hashtable,以字符串hashcode作为键,字符串引用作为值;Java堆中存储的就是普通的字符串对象。 那么如何判断字符串到底位于哪一个区域呢? 有以下几种情形。
情形一
String s="123";
复制代码
虚拟机在处理字面量"123"时,首先在本地栈中创建字符串"123",随后对其调用本地方法intern()。intern方法检查StringTable中是否存在这个字符串,如果有则返回对其的引用;如果没有,则将该字符串存入常量池中,并将其引用添加至StringTable中。 这里值得注意的是,如果该字符串已经存储于Java堆中,那么intern方法将不会再将其拷贝至常量池中,而是直接将其引用添加至StringTable中。
情形二
String s=new String("123");
复制代码
"123"按照情形一处理,返回对常量池中字符串常量"123"的引用。随后在Java堆中创建字符串对象,其内容与常量池中的"123"一致。
情形三
String s1=new String("123");
String s2=s1.intern();
复制代码
第一行按照情形二处理。经过情形二,将产生一个对象和一个常量。而s2将引用常量池中的字面量"123"。为了验证这一说法,进行如下实验:
String s1 = "123";
String s2 = s1.intern();
System.out.println(s1 == s2); // true
复制代码
String s1 = new String("123");
String s2 = s1.intern();
System.out.println(s1 == s2); // false
复制代码
实验结果证明了我们的说法。
情形四:
String s=new String("1")+new String("23");
复制代码
上述情况等价于以下代码:
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append("1").append("23");
String s=stringBuilder.toString();
复制代码
由于编译器的优化,将字符串拼接转换为StringBuilder操作。最后在Java堆中创建字符串对象。 最后看两个例子:
例子一:
String h = new String("12") + new String("3");
String h1 = new String("1") + new String("23");
String h3 = h.intern();
String h4 = h1.intern();
String h2 = "123";
System.out.println(h == h1); // false
System.out.println(h3 == h4); // true
System.out.println(h == h3); // true
System.out.println(h3 == h2); // true
复制代码
例子二:
String h = new String("12") + new String("3");
String h1 = new String("1") + new String("23");
String h2 = "123";
String h3 = h.intern();
String h4 = h1.intern();
System.out.println(h == h1); // false
System.out.println(h3 == h4); // true
System.out.println(h == h3); // false
System.out.println(h3 == h2); // true
复制代码
来源:java两个字符串对象相加和字符串字面量比较? - 海纳的回答 - 知乎 www.zhihu.com/question/26…
所有评论(0)