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多毫秒