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…

转载于:https://juejin.im/post/5c25983cf265da61715e66cb

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐