源代码
public class Main extends ClassLoader{
public static void main(String[] args){
String a = "a";
String b = "b";
String c = "ab";
}
}
反编译
public class Main extends ClassLoader{
public static void main(String[] args){
String a = "a";
String b = "b";
String ab = a+b;//new StringBuilder().append(a).append(b).toString();
String cd = "c"+"d";
}
}
intern方法会将字符串对象尝试放入串池,如果有则不会放入,如果没有则放入串池,最后将串池中的对象返回
public class Main extends ClassLoader{
public static void main(String[] args){
String a = new StringBuilder().append('a').toString();//通过StringBuilder构建的字符串对象不会放入串池中
String b = a.intern();
String c = "a";
System.out.println(b==a); // true,b是通过intern方法后从串池中得到的,之前串池中没有“a”,所以a变量指向的对象会放入串池中,然后的发哦a
System.out.println(c==a); //true,此时串池中的对象就是a
}
}
intern方法会将字符串对象放入串池,如果有则不会放入,如果没有则将此对象复制一份,然后将副本放入串池,会将串池中的对象返回
public class Main extends ClassLoader{
public static void main(String[] args){
String a = new StringBuilder().append('a').toString();//通过StringBuilder构建的字符串对象不会放入串池中
String b = a.intern();
String c = "a";
System.out.println(b==a); // false,a的副本放入了串池,所以a并不是串池中的对象,a仍然在堆中
System.out.println(c==a); //false,a的副本放入了串池,所以a并不是串池中的对象,a仍然在堆中
System.out.println(b==c); // true,b是通过intern方法得到的串池中的对象,c是通过字面量指向的串池中的对象
}
}
public class Main extends ClassLoader{
public static void main(String[] args){
String s1 = "a";
String s2 = "b";
String s3 = "a"+"b";
String s4 = s1+s2;
String s5 = "ab";
String s6 = s4.intern();
System.out.println(s3==s4); // false,s3通过编译器优化,运行时当作“ab”字面量,而s4会经过StringBuilder构建一个新的字符串对象,存在堆中
System.out.println(s3==s5); // true,s3和s5都指向串池中的“ab”
System.out.println(s3==s6); // true,s4调用intern方法会返回串池中的“ab”
}
}
虚拟机参数:
public class Main extends ClassLoader{
public static void main(String[] args){
int i=0;
try {
for (int j = 0; j < 10000; j++) {
// 往串池中添加字符串
String.valueOf(j).intern();
i++;
}
}catch (Throwable e){
e.printStackTrace();
}finally {
System.out.println(i);
}
}
}
-XX:StringTableSize=20000
,可以将桶个数改为两万个在大量字符串对象存在且重复时,重复的数据会占用大量的内存空间,使用StringTable是利用享元模式的思想,共享重复的数据,有利于节省空间