StringTable为字符串常量池,是运行时常量池的一部分,一般放String字符串对象

+ 运算符

两个 " " 相加

String s3="ab";
//["a","b","ab"]
String s4="a"+"b";
System.out.println(s3==s4);//true

s4="a"+"b"在编译时,会自动优化成"ab",查找常量池,如果没有存入,如果有则直接返回该对象

变量相加

String s1="a";
String s2="b";
//["a","b"]
String s3="ab";
String s5=s1+s2;
System.out.println(s3==s5);//false

s5运行时,调用new StringBuilder().append("a").append("b").toString(),实际上就是new String("ab"),创建实例对象,存在java堆中,而s3存在常量池中,故不相等

final 变量相加

String s1="a";
final String s2="b";
//["a","b"]
String s3="ab";
String s5="a"+s2;
System.out.println(s3==s5);//true

这里s2final修饰,在编译期就能被识别,然后情况同两个 " " 相加一样

intern() 方法

// jdk 1.8
String s1="a";
String s2="b";
//["a","b"]

String s5=s1+s2;//new String("ab")
//为堆中对象
String s6=s5.intern();
System.out.println(s5==s6);//true

intern()方法把对象放入字符串常量池,在jdk1.6和1.8中有不同的特性:

  • jdk 1.6:常量池中放入"ab",但 s5 仍为堆对象
  • jdk 1.8:常量池中放入"ab",同时 s5也为常量池对象

如果字符串池中已经存在,则直接返回该对象:

// jdk 1.8
String s1="a";
String s2="b";
String s3="ab";
//["a","b","ab"]

String s5=s1+s2;//new String("ab")
//为堆中对象
String s6=s5.intern();
System.out.println(s5==s6);//false

此时s5不做入池操作,仍为堆对象