String s1 = "ha";
String s2 = "ha";
String s3 = s1 +s2;
String s4 = "ha" + "ha";
String s5 = "haha";
String s6 = new String("haha");
System.out.println(s3 == s4);
System.out.println(s4 == s5);
System.out.println(s5 == s6);
输出:
false
true
false
s3本质调用了 new StringBuilder.append("a").append("b").toString(); 声明了新的引用变量,开辟了新的空间,所以指向的是堆中的对象地址而不是StringTable中的字符串了。
s6同理
s4 = "ha" + "ha";因为是两个常量拼接,在编译时就会直接变成"haha"进行处理,进入StringTable
s5 = "haha",因为也是常量,会先在StringTable中查找,找到后s5指向了StringTable中的"haha",因此s4 == s5返回true。
String.intern()方法,如果String在StringTable中不存在,则可以将这个String加入StringTable中,并返回这个对象。
比如上面的方法中加入s3.intern(),
String s1 = "ha";
String s2 = "ha";
String s3 = s1 +s2;
s3.intern();
String s4 = "ha" + "ha";
System.out.println(s3 == s4);
输出:
true
因为s3的值"haha"被放入了StringTable,s3指向了StringTable的"haha"对象
把haha变为main
String s1 = "ma"; String s2 = "in"; String s3 = s1 +s2; s3.intern(); String s4 = "ma" + "in"; System.out.println(s3 == s4);
输出:
main String,java等属于关键词,在一开始就在StringTable中存在了,所以s3.intern没能插入进去。
改回haha,如果再在s3前加入一个String ss = "haha";
String s1 = "ha";
String s2 = "ha";
String ss = "haha";
String s3 = s1 +s2;
s3.intern();
String s4 = "ha" + "ha";
System.out.println(s3 == s4);
输出:
false
因为s3.intern()执行时发现StringTable中有了"haha"了,所以没能加入成功,s3依旧是指向了堆内存中的对象。
-Xms500m 设置堆内存为500mb
-XX:StringTableSize=2000 将StringTable中的桶个数设为2000。 hash表桶的数量越多(数组部分长度越长),数据越分散,hashcode撞车的概率越小,速度越快。 默认值是6万多
-XX:+PrintStringTableStatistics 显示StringTable的状况。
StringTable有内存回收机制
打开“Run->Edit Configurations”菜单
在VM option(虚拟机设置)中,加入代码:-XX:StringTableSize=2000 ,点击ok,然后运行下面的代码
long t1 = new Date().getTime(); String[] a = new String[1000000]; for(int i=0; i<1000000; i++){ a[i] = ("" + i).intern(); } long t2 = new Date().getTime(); System.out.println(t2 - t1);
运行时间为9000多毫秒。
然后修改VM option:-XX:StringTableSize=20000,点击ok,然后再尝试
运行时间为1000多毫秒
然后修改VM option:-XX:StringTableSize=200000,点击ok,然后再尝试
运行时间为400多毫秒