Java String 面面觀

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文主要介紹"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中與字符串相關的一些內容,主要包括"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類的實現及其不變性、"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"相關類("},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"StringBuffer"}]},{"type":"text","text":")的實現 以及 字符串緩存機制的用法與實現。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"String類的設計與實現"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類的核心邏輯是通過對"},{"type":"codeinline","content":[{"type":"text","text":"char"}]},{"type":"text","text":"型數組進行封裝來實現字符串對象,但實現細節伴隨着"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"版本的演進也發生過幾次變化。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Java 6"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public final class String implements java.io.Serializable, Comparable, CharSequence\n{\n /** The value is used for character storage. */\n private final char value[];\n /** The offset is the first index of the storage that is used. */\n private final int offset;\n /** The count is the number of characters in the String. */\n private final int count;\n /** Cache the hash code for the string */\n private int hash; // Default to 0\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"中,"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類有四個成員變量:"},{"type":"codeinline","content":[{"type":"text","text":"char"}]},{"type":"text","text":"型數組"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"、偏移量 "},{"type":"codeinline","content":[{"type":"text","text":"offset"}]},{"type":"text","text":"、字符數量 "},{"type":"codeinline","content":[{"type":"text","text":"count"}]},{"type":"text","text":"、哈希值 "},{"type":"codeinline","content":[{"type":"text","text":"hash"}]},{"type":"text","text":"。"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組用來存儲字符序列, "},{"type":"codeinline","content":[{"type":"text","text":"offset"}]},{"type":"text","text":" 和 "},{"type":"codeinline","content":[{"type":"text","text":"count"}]},{"type":"text","text":" 兩個屬性用來定位字符串在"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組中的位置,"},{"type":"codeinline","content":[{"type":"text","text":"hash"}]},{"type":"text","text":"屬性用來緩存字符串的"},{"type":"codeinline","content":[{"type":"text","text":"hashCode"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用"},{"type":"codeinline","content":[{"type":"text","text":"offset"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"count"}]},{"type":"text","text":"來定位"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組的目的是,可以高效、快速地共享"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組,例如"},{"type":"codeinline","content":[{"type":"text","text":"substring()"}]},{"type":"text","text":"方法返回的子字符串是通過記錄"},{"type":"codeinline","content":[{"type":"text","text":"offset"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"count"}]},{"type":"text","text":"來實現與原字符串共享"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組的,而不是重新拷貝一份。"},{"type":"codeinline","content":[{"type":"text","text":"substring()"}]},{"type":"text","text":"方法實現如下:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String(int offset, int count, char value[]) {\n\tthis.value = value; // 直接複用原數組\n\tthis.offset = offset;\n\tthis.count = count;\n}\npublic String substring(int beginIndex, int endIndex) {\n // ...... 省略一些邊界檢查的代碼 ......\n return ((beginIndex == 0) && (endIndex == count)) ? this :\n new String(offset + beginIndex, endIndex - beginIndex, value);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是這種方式卻很有可能會導致內存泄漏。例如在如下代碼中:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String bigStr = new String(new char[100000]);\nString subStr = bigStr.substring(0,2);\nbigStr = null;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"bigStr"}]},{"type":"text","text":"被設置爲"},{"type":"codeinline","content":[{"type":"text","text":"null"}]},{"type":"text","text":"之後,其中的"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組卻仍然被"},{"type":"codeinline","content":[{"type":"text","text":"subStr"}]},{"type":"text","text":"所引用,導致垃圾回收器無法將其回收,結果雖然我們實際上僅僅需要"},{"type":"codeinline","content":[{"type":"text","text":"2"}]},{"type":"text","text":"個字符的空間,但是實際卻佔用了"},{"type":"codeinline","content":[{"type":"text","text":"100000"}]},{"type":"text","text":"個字符的空間。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"中,如果想要避免這種內存泄漏情況的發生,可以使用下面的方式:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String subStr = bigStr.substring(0,2) + \"\";\n// 或者\nString subStr = new String(bigStr.substring(0,2));"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在語句執行完之後,"},{"type":"codeinline","content":[{"type":"text","text":"substring"}]},{"type":"text","text":"方法返回的匿名"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象由於沒有被別的對象引用,所以能夠被垃圾回收器回收,不會繼續引用"},{"type":"codeinline","content":[{"type":"text","text":"bigStr"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組,從而避免了內存泄漏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Java 7 & Java 8"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public final class String implements java.io.Serializable, Comparable, CharSequence {\n /** The value is used for character storage. */\n private final char value[];\n /** Cache the hash code for the string */\n private int hash; // Default to 0\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"Java 7"}]},{"type":"text","text":"-"},{"type":"codeinline","content":[{"type":"text","text":"Java 8"}]},{"type":"text","text":"中,"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":" 對 "},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":" 類做了一些改變。"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":" 類中不再有 "},{"type":"codeinline","content":[{"type":"text","text":"offset"}]},{"type":"text","text":" 和 "},{"type":"codeinline","content":[{"type":"text","text":"count"}]},{"type":"text","text":" 兩個成員變量了。"},{"type":"codeinline","content":[{"type":"text","text":"substring()"}]},{"type":"text","text":"方法也不再共享 "},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組,而是從指定位置重新拷貝一份"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組,從而解決了使用該方法可能導致的內存泄漏問題。"},{"type":"codeinline","content":[{"type":"text","text":"substring()"}]},{"type":"text","text":"方法實現如下:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public String(char value[], int offset, int count) {\n // ...... 省略一些邊界檢查的代碼 ......\n\n // 從原數組拷貝\n this.value = Arrays.copyOfRange(value, offset, offset+count); \n}\npublic String substring(int beginIndex, int endIndex) {\n // ...... 省略一些邊界檢查的代碼 ......\n return ((beginIndex == 0) && (endIndex == value.length)) ? this\n : new String(value, beginIndex, subLen);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Java 9"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public final class String implements java.io.Serializable, Comparable, CharSequence {\n /** The value is used for character storage. */\n private final byte[] value;\n /** The identifier of the encoding used to encode the bytes in {@code value}. */\n private final byte coder;\n /** Cache the hash code for the string */\n private int hash; // Default to 0\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了節省內存空間,"},{"type":"codeinline","content":[{"type":"text","text":"Java 9"}]},{"type":"text","text":"中對"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"的實現方式做了優化,"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"成員變量從"},{"type":"codeinline","content":[{"type":"text","text":"char[]"}]},{"type":"text","text":"類型改爲了"},{"type":"codeinline","content":[{"type":"text","text":"byte[]"}]},{"type":"text","text":"類型,同時新增了一個"},{"type":"codeinline","content":[{"type":"text","text":"coder"}]},{"type":"text","text":"成員變量。我們知道"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中"},{"type":"codeinline","content":[{"type":"text","text":"char"}]},{"type":"text","text":"類型佔用的是兩個字節,對於只佔用一個字節的字符(例如,"},{"type":"codeinline","content":[{"type":"text","text":"a-z"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"A-Z"}]},{"type":"text","text":")就顯得有點浪費,所以"},{"type":"codeinline","content":[{"type":"text","text":"Java 9"}]},{"type":"text","text":"中將"},{"type":"codeinline","content":[{"type":"text","text":"char[]"}]},{"type":"text","text":"改爲"},{"type":"codeinline","content":[{"type":"text","text":"byte[]"}]},{"type":"text","text":"來存儲字符序列,而新屬性 "},{"type":"codeinline","content":[{"type":"text","text":"coder"}]},{"type":"text","text":" 的作用就是用來表示"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組中存儲的是雙字節編碼的字符還是單字節編碼的字符。"},{"type":"codeinline","content":[{"type":"text","text":"coder"}]},{"type":"text","text":" 屬性可以有 "},{"type":"codeinline","content":[{"type":"text","text":"0"}]},{"type":"text","text":" 和 "},{"type":"codeinline","content":[{"type":"text","text":"1"}]},{"type":"text","text":" 兩個值,"},{"type":"codeinline","content":[{"type":"text","text":"0"}]},{"type":"text","text":" 代表 "},{"type":"codeinline","content":[{"type":"text","text":"Latin-1"}]},{"type":"text","text":"(單字節編碼),"},{"type":"codeinline","content":[{"type":"text","text":"1"}]},{"type":"text","text":" 代表 "},{"type":"codeinline","content":[{"type":"text","text":"UTF-16"}]},{"type":"text","text":"(雙字節編碼)。在創建字符串的時候如果判斷所有字符都可以用單字節來編碼,則使用"},{"type":"codeinline","content":[{"type":"text","text":"Latin-1"}]},{"type":"text","text":"來編碼以壓縮空間,否則使用"},{"type":"codeinline","content":[{"type":"text","text":"UTF-16"}]},{"type":"text","text":"編碼。主要的構造函數實現如下:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String(char[] value, int off, int len, Void sig) {\n if (len == 0) {\n this.value = \"\".value;\n this.coder = \"\".coder;\n return;\n }\n if (COMPACT_STRINGS) {\n byte[] val = StringUTF16.compress(value, off, len); // 嘗試壓縮字符串,使用單字節編碼存儲\n if (val != null) { // 壓縮成功,可以使用單字節編碼存儲\n this.value = val;\n this.coder = LATIN1;\n return;\n }\n }\n // 否則,使用雙字節編碼存儲\n this.coder = UTF16;\n this.value = StringUTF16.toBytes(value, off, len);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"String類的不變性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們注意到"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類是用"},{"type":"codeinline","content":[{"type":"text","text":"final"}]},{"type":"text","text":"修飾的;所有的屬性都是聲明爲"},{"type":"codeinline","content":[{"type":"text","text":"private"}]},{"type":"text","text":"的;並且除了"},{"type":"codeinline","content":[{"type":"text","text":"hash"}]},{"type":"text","text":"屬性之外的其他屬性也都是用"},{"type":"codeinline","content":[{"type":"text","text":"final"}]},{"type":"text","text":"修飾。這保證了:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類由"},{"type":"codeinline","content":[{"type":"text","text":"final"}]},{"type":"text","text":"修飾,所以無法通過繼承"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類改變其語義;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"所有的屬性都是聲明爲"},{"type":"codeinline","content":[{"type":"text","text":"private"}]},{"type":"text","text":"的, 所以無法在"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"外部"},{"type":"text","marks":[{"type":"strong"}],"text":"直接"},{"type":"text","text":"訪問或修改其屬性;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"除了"},{"type":"codeinline","content":[{"type":"text","text":"hash"}]},{"type":"text","text":"屬性之外的其他屬性都是用"},{"type":"codeinline","content":[{"type":"text","text":"final"}]},{"type":"text","text":"修飾,表示這些屬性在初始化賦值後不可以再修改。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述的定義共同實現了"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類一個重要的特性 —— **不變性**,即 "},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":" 對象一旦創建成功,就不能再對它進行任何修改。"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"提供的方法"},{"type":"codeinline","content":[{"type":"text","text":"substring()"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"concat()"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"replace()"}]},{"type":"text","text":"等方法返回值都是新創建的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,而不是原來的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"hash"}]},{"type":"text","text":"屬性不是"},{"type":"codeinline","content":[{"type":"text","text":"final"}]},{"type":"text","text":"的原因是:"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"hashCode"}]},{"type":"text","text":"並不需要在創建字符串時立即計算並賦值,而是在"},{"type":"codeinline","content":[{"type":"text","text":"hashCode()"}]},{"type":"text","text":"方法被調用時才需要進行計算。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"爲什麼String類要設計爲不可變的?"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"保證 "},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":" 對象的安全性。"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"被廣泛用作"},{"type":"codeinline","content":[{"type":"text","text":"JDK"}]},{"type":"text","text":"中作爲參數、返回值,例如網絡連接,打開文件,類加載,等等。如果 "},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":" 對象是可變的,那麼 "},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":" 對象將可能被惡意修改,引發安全問題。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"線程安全。"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類的不可變性天然地保證了其線程安全的特性。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"保證了"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象的"},{"type":"codeinline","content":[{"type":"text","text":"hashCode"}]},{"type":"text","text":"的不變性。"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類的不可變性,保證了其"},{"type":"codeinline","content":[{"type":"text","text":"hashCode"}]},{"type":"text","text":"值能夠在第一次計算後進行緩存,之後無需重複計算。這使得"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象很適合用作"},{"type":"codeinline","content":[{"type":"text","text":"HashMap"}]},{"type":"text","text":"等容器的"},{"type":"codeinline","content":[{"type":"text","text":"Key"}]},{"type":"text","text":",並且相比其他對象效率更高。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"實現"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"。"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"爲字符串對象設計了"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"來共享字符串,節省內存空間。如果字符串是可變的,那麼字符串對象便無法共享。因爲如果改變了其中一個對象的值,那麼其他對象的值也會相應發生變化。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"與String類相關的類"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類之外,還有兩個與"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類相關的的類:"},{"type":"codeinline","content":[{"type":"text","text":"StringBuffer"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":",這兩個類可以看作是"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類的可變版本,提供了對字符串修改的各種方法。兩者的區別在於"},{"type":"codeinline","content":[{"type":"text","text":"StringBuffer"}]},{"type":"text","text":"是線程安全的而"},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":"不是線程安全的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"StringBuffer / StringBuilder的實現"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"StringBuffer"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":"都是繼承自"},{"type":"codeinline","content":[{"type":"text","text":"AbstractStringBuilder"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"AbstractStringBuilder"}]},{"type":"text","text":"利用可變的"},{"type":"codeinline","content":[{"type":"text","text":"char"}]},{"type":"text","text":"數組("},{"type":"codeinline","content":[{"type":"text","text":"Java 9"}]},{"type":"text","text":"之後改爲爲"},{"type":"codeinline","content":[{"type":"text","text":"byte"}]},{"type":"text","text":"數組)來實現對字符串的各種修改操作。"},{"type":"codeinline","content":[{"type":"text","text":"StringBuffer"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":"都是調用"},{"type":"codeinline","content":[{"type":"text","text":"AbstractStringBuilder"}]},{"type":"text","text":"中的方法來操作字符串, 兩者區別在於"},{"type":"codeinline","content":[{"type":"text","text":"StringBuffer"}]},{"type":"text","text":"類中對字符串修改的方法都加了"},{"type":"codeinline","content":[{"type":"text","text":"synchronized"}]},{"type":"text","text":"修飾,而"},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":"沒有,所以"},{"type":"codeinline","content":[{"type":"text","text":"StringBuffer"}]},{"type":"text","text":"是線程安全的,而"},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":"並非線程安全的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們以"},{"type":"codeinline","content":[{"type":"text","text":"Java 8"}]},{"type":"text","text":"爲例,看一下"},{"type":"codeinline","content":[{"type":"text","text":"AbstractStringBuilder"}]},{"type":"text","text":"類的實現:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"abstract class AbstractStringBuilder implements Appendable, CharSequence {\n /** The value is used for character storage. */\n char[] value;\n /** The count is the number of characters used. */\n int count;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組用來存儲字符序列,"},{"type":"codeinline","content":[{"type":"text","text":"count"}]},{"type":"text","text":"則用來存儲"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組中已經使用的字符數量,字符串真實的內容是"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組中"},{"type":"codeinline","content":[{"type":"text","text":"[0,count)"}]},{"type":"text","text":"之間的字符序列,而"},{"type":"codeinline","content":[{"type":"text","text":"[count,length)"}]},{"type":"text","text":"之間是**未使用**的空間。需要"},{"type":"codeinline","content":[{"type":"text","text":"count"}]},{"type":"text","text":"屬性記錄已使用空間的原因是,"},{"type":"codeinline","content":[{"type":"text","text":"AbstractStringBuilder"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組並不是每次修改都會重新申請,而是會提前預分配一定的多餘空間,以此來減少重新分配數組空間的次數。(這種做法類似於"},{"type":"codeinline","content":[{"type":"text","text":"ArrayList"}]},{"type":"text","text":"的實現)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組擴容的策略是:當對字符串進行修改時,如果當前的"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組不滿足空間需求時,則會重新分配更大的"},{"type":"codeinline","content":[{"type":"text","text":"value"}]},{"type":"text","text":"數組,分配的數組大小爲"},{"type":"codeinline","content":[{"type":"text","text":"min( 原數組大小×2 + 2 , 所需的數組大小 )"}]},{"type":"text","text":",更加細節的邏輯可以參考如下代碼:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;\n\nprivate int newCapacity(int minCapacity) {\n // overflow-conscious code\n int newCapacity = (value.length << 1) + 2; //原數組大小×2 + 2 \n if (newCapacity - minCapacity < 0) { // 如果小於所需空間大小,擴展至所需空間大小\n newCapacity = minCapacity;\n }\n return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)\n ? hugeCapacity(minCapacity)\n : newCapacity;\n}\n\nprivate int hugeCapacity(int minCapacity) {\n if (Integer.MAX_VALUE - minCapacity < 0) { // overflow\n throw new OutOfMemoryError();\n }\n return (minCapacity > MAX_ARRAY_SIZE)\n ? minCapacity : MAX_ARRAY_SIZE;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然"},{"type":"codeinline","content":[{"type":"text","text":"AbstractStringBuilder"}]},{"type":"text","text":"也提供了"},{"type":"codeinline","content":[{"type":"text","text":"trimToSize"}]},{"type":"text","text":"方法去釋放多餘的空間:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public void trimToSize() {\n if (count < value.length) {\n value = Arrays.copyOf(value, count);\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"String對象的緩存機制"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象的使用廣泛,"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"爲"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象設計了緩存機制,以提升時間和空間上的效率。在"},{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"text","text":"的運行時數據區中存在一個"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"("},{"type":"codeinline","content":[{"type":"text","text":"String Pool"}]},{"type":"text","text":"),在這個常量池中維護了所有已經緩存的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,當我們說一個"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象被緩存("},{"type":"codeinline","content":[{"type":"text","text":"interned"}]},{"type":"text","text":")了,就是指它進入了"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們通過解答下面三個問題來理解"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象的緩存機制:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"哪些"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象會被緩存進"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象被緩存在哪裏,如何組織起來的?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象是什麼時候進入"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"的?"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"說明"},{"type":"text","text":": 如未特殊指明,本文中提及的"},{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"text","text":"實現均指的是"},{"type":"codeinline","content":[{"type":"text","text":"Oracle"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"HotSpot VM"}]},{"type":"text","text":",並且不考慮 逃逸分析("},{"type":"codeinline","content":[{"type":"text","text":"escape analysis"}]},{"type":"text","text":")、標量替換("},{"type":"codeinline","content":[{"type":"text","text":"scalar replacement"}]},{"type":"text","text":")、無用代碼消除("},{"type":"codeinline","content":[{"type":"text","text":"dead-code elimination"}]},{"type":"text","text":")等優化手段,測試代碼基於不添加任何額外"},{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"text","text":"參數的情況下運行。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"預備知識"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了更好的閱讀體驗,在解答上面三個問題前,希望讀者對以下知識點有簡單瞭解:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"text","text":"運行時數據區"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"的結構"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"text","text":"基於棧的字節碼解釋執行引擎"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"類加載的過程"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中的幾種常量池"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了內容的完整性,我們對下文涉及較多的其中兩點做簡要介紹。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"類加載的過程 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"類從被加載到虛擬機內存中開始,到卸載出內存爲止,它的整個生命週期依次爲:加載("},{"type":"codeinline","content":[{"type":"text","text":"Loading"}]},{"type":"text","text":")、驗證("},{"type":"codeinline","content":[{"type":"text","text":"Verification"}]},{"type":"text","text":")、準備("},{"type":"codeinline","content":[{"type":"text","text":"Preparation"}]},{"type":"text","text":")、解析("},{"type":"codeinline","content":[{"type":"text","text":"Resolution"}]},{"type":"text","text":")、初始化("},{"type":"codeinline","content":[{"type":"text","text":"Initialization"}]},{"type":"text","text":")、使用("},{"type":"codeinline","content":[{"type":"text","text":"Using"}]},{"type":"text","text":")和卸載("},{"type":"codeinline","content":[{"type":"text","text":"Unloading"}]},{"type":"text","text":")7個階段。其中驗證、準備、解析3個部分統稱爲連接("},{"type":"codeinline","content":[{"type":"text","text":"Linking"}]},{"type":"text","text":")。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"加載、驗證、準備、初始化和卸載這5個階段的順序是確定的,類的加載過程必須按照這種順序按部就班地開始,而解析階段則不一定:它在某些情況下可以在初始化階段之後再開始,這是爲了支持Java語言的運行時綁定(也稱爲動態綁定或晚期綁定)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Java中的幾種常量池"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"1. class文件中的常量池"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們知道"},{"type":"codeinline","content":[{"type":"text","text":"java"}]},{"type":"text","text":"後綴的源代碼文件會被"},{"type":"codeinline","content":[{"type":"text","text":"javac"}]},{"type":"text","text":"編譯爲"},{"type":"codeinline","content":[{"type":"text","text":"class"}]},{"type":"text","text":"後綴的"},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"(字節碼文件)。在"},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"中有一部分內容是 "},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4","title":""},"content":[{"type":"text","text":"常量池(Constant Pool)"}]},{"type":"text","text":" ,這個常量池中主要存儲兩大類常量:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼中的"},{"type":"codeinline","content":[{"type":"text","text":"字面量"}]},{"type":"text","text":"或者"},{"type":"codeinline","content":[{"type":"text","text":"常量表達式"}]},{"type":"text","text":"的值;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"符號引用,包括:類和接口的全限定名、字段的名稱和描述符、方法的名稱和描述符等。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"2. 運行時常量池"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5","title":""},"content":[{"type":"text","text":"運行時數據區(Run-Time Data Areas)"}]},{"type":"text","text":"中,有一部分是[運行時常量池(Run-Time Constant Pool)](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.5),屬於"},{"type":"codeinline","content":[{"type":"text","text":"方法區"}]},{"type":"text","text":"的一部分。"},{"type":"codeinline","content":[{"type":"text","text":"運行時常量池"}]},{"type":"text","text":"是"},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"中每個類或者接口的常量池("},{"type":"codeinline","content":[{"type":"text","text":"Constant Pool"}]},{"type":"text","text":" )的運行時表示形式,"},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"的常量池中的內容會在類加載後進入方法區的"},{"type":"codeinline","content":[{"type":"text","text":"運行時常量池"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"3. 字符串常量池"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"("},{"type":"codeinline","content":[{"type":"text","text":"String Pool"}]},{"type":"text","text":")也就是我們上文提到的用來緩存"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象的常量池。 這個常量池是全局共享的,屬於運行時數據區的一部分。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"哪些String對象會被緩存進字符串常量池?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中,有兩種字符串會被緩存到"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中,一種是在代碼中定義的"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"或者"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":",另一種是程序中主動調用"},{"type":"codeinline","content":[{"type":"text","text":"String.intern()"}]},{"type":"text","text":"方法將當前"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象緩存到"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中。下面分別對兩種方式做簡要介紹。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1. 隱式緩存 - 字符串字面量 或者 字符串常量表達式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之所以稱之爲隱式緩存是因爲我們並不需要主動去編寫緩存相關代碼,編譯器和"},{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"text","text":"會幫我們完成這部分工作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"字符串字面量"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第一種會被隱式緩存的字符串是 "},{"type":"text","marks":[{"type":"strong"}],"text":"字符串字面量"},{"type":"text","text":"。"},{"type":"codeinline","content":[{"type":"text","text":"字面量"}]},{"type":"text","text":" 是類型爲原始類型、"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類型、"},{"type":"codeinline","content":[{"type":"text","text":"null"}]},{"type":"text","text":"類型的值在源代碼中的表示形式。例如:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"int i = 100; // int 類型字面量\ndouble f = 10.2; // double 類型字面量\nboolean b = true; // boolean 類型字面量\nString s = \"hello\"; // String類型字面量\nObject o = null; // null類型字面量"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"是由雙引號括起來的"},{"type":"codeinline","content":[{"type":"text","text":"0"}]},{"type":"text","text":"個或者多個字符構成的。 "},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"會在執行過程中爲"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"創建"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象並加入"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中。例如上面代碼中的"},{"type":"codeinline","content":[{"type":"text","text":"\"hello\""}]},{"type":"text","text":"就是一個"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":",在執行過程中會先 創建一個內容爲"},{"type":"codeinline","content":[{"type":"text","text":"\"hello\""}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,並緩存到"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中,再將"},{"type":"codeinline","content":[{"type":"text","text":"s"}]},{"type":"text","text":"引用指向這個"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"更加詳細的內容請參閱"},{"type":"codeinline","content":[{"type":"text","text":"Java語言規範"}]},{"type":"text","text":"("},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5","title":""},"content":[{"type":"text","text":"JLS - 3.10.5. String Literals"}]},{"type":"text","text":")。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"字符串常量表達式"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外一種會被隱式緩存的字符串是 "},{"type":"text","marks":[{"type":"strong"}],"text":"字符串常量表達式"},{"type":"text","text":"。"},{"type":"codeinline","content":[{"type":"text","text":"常量表達式"}]},{"type":"text","text":"指的是表示簡單類型值或"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象的表達式,可以簡單理解爲"},{"type":"codeinline","content":[{"type":"text","text":"常量表達式"}]},{"type":"text","text":"就是在編譯期間就能確定值的表達式。"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":"就是表示"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象的常量表達式。例如:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"int a = 1 + 2;\ndouble d = 10 + 2.01;\nboolean b = true & false;\nString str1 = \"abc\" + 123;\n\nfinal int num = 456;\nString str2 = \"abc\" +456;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"會在執行過程中爲"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":"創建"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象並加入"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中。例如,上面的代碼中,會分別創建"},{"type":"codeinline","content":[{"type":"text","text":"\"abc123\""}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"\"abc456\""}]},{"type":"text","text":"兩個"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,這兩個"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象會被緩存到"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中,"},{"type":"codeinline","content":[{"type":"text","text":"str1"}]},{"type":"text","text":"會指向常量池中值爲"},{"type":"codeinline","content":[{"type":"text","text":"\"abc123\""}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,"},{"type":"codeinline","content":[{"type":"text","text":"str2"}]},{"type":"text","text":"會指向常量池中值爲"},{"type":"codeinline","content":[{"type":"text","text":"\"abc456\""}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於"},{"type":"codeinline","content":[{"type":"text","text":"常量表達式"}]},{"type":"text","text":"更加詳細的內容請參閱"},{"type":"codeinline","content":[{"type":"text","text":"Java語言規範"}]},{"type":"text","text":"("},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28","title":""},"content":[{"type":"text","text":"JLS - 15.28 Constant Expressions"}]},{"type":"text","text":")。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2. 主動緩存 - String.intern()方法"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了聲明爲"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":"之外,通過其他方式得到的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象也可以主動加入"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中。例如:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String str = new String(\"123\") + new String(\"456\");\nstr.intern();"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在上面的代碼中,在執行完第一句後,常量池中存在內容爲"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"\"456\""}]},{"type":"text","text":"的兩個"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,但是不存在"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,但在執行完"},{"type":"codeinline","content":[{"type":"text","text":"str.intern();"}]},{"type":"text","text":"之後,內容爲"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象也加入到了"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們通過"},{"type":"codeinline","content":[{"type":"text","text":"String.intern()"}]},{"type":"text","text":"方法的註釋來看下其具體的緩存機制:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true."}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡單翻譯一下:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當調用 "},{"type":"codeinline","content":[{"type":"text","text":"intern"}]},{"type":"text","text":" 方法時,如果常量池中已經包含相同內容的字符串(字符串內容相同由 "},{"type":"codeinline","content":[{"type":"text","text":"equals (Object)"}]},{"type":"text","text":" 方法確定,對於 "},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":" 對象來說,也就是字符序列相同),則返回常量池中的字符串對象。否則,將此 "},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":" 對象將添加到常量池中,並返回此 "},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":" 對象的引用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,對於任意兩個字符串 "},{"type":"codeinline","content":[{"type":"text","text":"s"}]},{"type":"text","text":" 和 "},{"type":"codeinline","content":[{"type":"text","text":"t"}]},{"type":"text","text":",當且僅當 "},{"type":"codeinline","content":[{"type":"text","text":"s.equals(t)"}]},{"type":"text","text":"的結果爲"},{"type":"codeinline","content":[{"type":"text","text":"true"}]},{"type":"text","text":"時,"},{"type":"codeinline","content":[{"type":"text","text":"s.intern() == t.intern()"}]},{"type":"text","text":"的結果爲"},{"type":"codeinline","content":[{"type":"text","text":"true"}]},{"type":"text","text":"。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"String對象被緩存在哪裏,如何組織起來的?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"HotSpot VM"}]},{"type":"text","text":"中,有一個用來記錄緩存的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象的全局表,叫做"},{"type":"codeinline","content":[{"type":"text","text":"StringTable"}]},{"type":"text","text":",結構及實現方式都類似於"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"HashMap"}]},{"type":"text","text":"或者"},{"type":"codeinline","content":[{"type":"text","text":"HashSet"}]},{"type":"text","text":",是一個使用拉鍊法解決哈希衝突的哈希表,可以簡單理解爲"},{"type":"codeinline","content":[{"type":"text","text":"HashSet"}]},{"type":"text","text":",注意它只存儲對"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象的引用,而不存儲"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象實例。 一般我們說一個字符串進入了"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"其實是說在這個"},{"type":"codeinline","content":[{"type":"text","text":"StringTable"}]},{"type":"text","text":"中保存了對它的引用,反之,如果說沒有在其中就是說"},{"type":"codeinline","content":[{"type":"text","text":"StringTable"}]},{"type":"text","text":"中沒有對它的引用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而真正的字符串對象其實是保存在另外的區域中的,在"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"中"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象是存儲在"},{"type":"codeinline","content":[{"type":"text","text":"永久代"}]},{"type":"text","text":"("},{"type":"codeinline","content":[{"type":"text","text":"Java 8"}]},{"type":"text","text":"之前"},{"type":"codeinline","content":[{"type":"text","text":"HotSpot VM"}]},{"type":"text","text":"對"},{"type":"codeinline","content":[{"type":"text","text":"方法區"}]},{"type":"text","text":"的實現)中的,而在"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"之後,"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象是存儲在"},{"type":"codeinline","content":[{"type":"text","text":"堆"}]},{"type":"text","text":"中的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Java 7"}]},{"type":"text","text":"中將"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的對象移動到"},{"type":"codeinline","content":[{"type":"text","text":"堆"}]},{"type":"text","text":"中的原因是在 "},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"中,"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的對象在"},{"type":"codeinline","content":[{"type":"text","text":"永久代"}]},{"type":"text","text":"創建,而"},{"type":"codeinline","content":[{"type":"text","text":"永久代"}]},{"type":"text","text":"代的大小一般不會設置太大,如果大量使用字符串緩存將可能對導致"},{"type":"codeinline","content":[{"type":"text","text":"永久代"}]},{"type":"text","text":"發生"},{"type":"codeinline","content":[{"type":"text","text":"OOM"}]},{"type":"text","text":"異常。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"String對象是什麼時候進入字符串常量池的?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於通過 在程序中調用"},{"type":"codeinline","content":[{"type":"text","text":"String.intern()"}]},{"type":"text","text":"方法主動緩存進入常量池的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,很顯然就是在調用"},{"type":"codeinline","content":[{"type":"text","text":"intern()"}]},{"type":"text","text":"方法的時候進入常量池的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們重點來研究一下會被隱式緩存的兩種值("},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":"),主要是兩個問題:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"我們並沒有主動調用"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類的構造方法,那麼它們是在何時被創建?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"它們是在何時進入"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"的?"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們以下面的代碼爲例來分析這兩個問題:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class Main {\n public static void main(String[] args) {\n String str1 = \"123\" + 123; // 字符串常量表達式\n String str2 = \"123456\"; // 字面量\n String str3 = \"123\" + 456; //字符串常量表達式\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"字節碼分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們對上述代碼編譯之後使用"},{"type":"codeinline","content":[{"type":"text","text":"javap"}]},{"type":"text","text":"來觀察一下字節碼文件,爲了節省篇幅,只摘取了相關的部分:常量池表部分以及"},{"type":"codeinline","content":[{"type":"text","text":"main"}]},{"type":"text","text":"方法信息部分:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"Constant pool:\n #1 = Methodref #5.#23 // java/lang/Object.\"\":()V\n #2 = String #24 // 123123\n #3 = String #25 // 123456\n // ...... 省略 ......\n #24 = Utf8 123123\n #25 = Utf8 123456\n \n // ...... 省略 ......\n\n public static void main(java.lang.String[]);\n descriptor: ([Ljava/lang/String;)V\n flags: ACC_PUBLIC, ACC_STATIC\n Code:\n stack=1, locals=4, args_size=1\n 0: ldc #2 // String 123123\n 2: astore_1\n 3: ldc #3 // String 123456\n 5: astore_2\n 6: ldc #3 // String 123456\n 8: astore_3\n 9: return\n LineNumberTable:\n line 7: 0\n line 8: 3\n line 9: 6\n line 10: 9\n LocalVariableTable:\n Start Length Slot Name Signature\n 0 10 0 args [Ljava/lang/String;\n 3 7 1 str1 Ljava/lang/String;\n 6 4 2 str2 Ljava/lang/String;\n 9 1 3 str3 Ljava/lang/String;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"常量池"}]},{"type":"text","text":"中,有兩種與字符串相關的常量類型,"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_String"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Utf8"}]},{"type":"text","text":"。"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_String"}]},{"type":"text","text":"類型的常量用於表示"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類型的常量對象,其內容只是一個常量池的索引值"},{"type":"codeinline","content":[{"type":"text","text":"index"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"index"}]},{"type":"text","text":"處的成員必須是"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Utf8"}]},{"type":"text","text":"類型。而"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Utf8"}]},{"type":"text","text":"類型的常量用於存儲真正的字符串內容。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如,上面的常量池中的第"},{"type":"codeinline","content":[{"type":"text","text":"2"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"3"}]},{"type":"text","text":"項是"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_String"}]},{"type":"text","text":"類型,存儲的索引分別爲"},{"type":"codeinline","content":[{"type":"text","text":"24"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"25"}]},{"type":"text","text":",常量池中第"},{"type":"codeinline","content":[{"type":"text","text":"24"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"25"}]},{"type":"text","text":"項就是"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Utf8"}]},{"type":"text","text":",存儲的值分別爲"},{"type":"codeinline","content":[{"type":"text","text":"\"123123\""}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"的方法信息中"},{"type":"codeinline","content":[{"type":"text","text":"Code"}]},{"type":"text","text":"屬性是"},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"中最爲重要的部分之一,其中包含了執行語句對應的虛擬機指令,異常表,本地變量信息等,其中"},{"type":"codeinline","content":[{"type":"text","text":"LocalVariableTable"}]},{"type":"text","text":"是本地變量的信息,"},{"type":"codeinline","content":[{"type":"text","text":"Slot"}]},{"type":"text","text":"可以理解爲本地變量表中的索引位置。"},{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令的作用是從"},{"type":"codeinline","content":[{"type":"text","text":"運行時常量池"}]},{"type":"text","text":"中提取指定索引位置的數據並壓入棧中;"},{"type":"codeinline","content":[{"type":"text","text":"astore_"}]},{"type":"text","text":"指令的作用是將一個引用類型的值從棧中彈出並保存到本地變量表的指定位置,也就是"},{"type":"codeinline","content":[{"type":"text","text":""}]},{"type":"text","text":"指定的位置。可以看出三條賦值語句所對應的字節碼指令其實都是相同的:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"ldc # // 首先將常量池中指定索引位置的String對象壓入棧中\nastore_ // 然後從棧中彈出剛剛存入的String對象保存到本地變量的指定位置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"運行過程分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還是圍繞上面的代碼,我們結合 從編譯到執行的過程 來分析一下"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":"的"},{"type":"text","marks":[{"type":"strong"}],"text":"創建"},{"type":"text","text":"及*"},{"type":"text","marks":[{"type":"italic"}],"text":"緩存"},{"type":"text","text":"*時機。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"1. 編譯"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先,第一步是"},{"type":"codeinline","content":[{"type":"text","text":"javac"}]},{"type":"text","text":"將源代碼編譯爲"},{"type":"codeinline","content":[{"type":"text","text":"class"}]},{"type":"text","text":"文件。在源代碼編譯過程中,我們上文提到的兩種值 "},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"("},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":") 和 "},{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":"("},{"type":"codeinline","content":[{"type":"text","text":"\"123\" + 456"}]},{"type":"text","text":")這兩類值都會存在編譯後的"},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"的常量池中,常量類型爲"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_String"}]},{"type":"text","text":"。值得注意的兩點是:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":"會在編譯期計算出真實值存在"},{"type":"codeinline","content":[{"type":"text","text":"class"}]},{"type":"text","text":"文件的"},{"type":"codeinline","content":[{"type":"text","text":"常量池"}]},{"type":"text","text":"中。例如上面源代碼中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123\" + 123"}]},{"type":"text","text":"這個表達式在"},{"type":"codeinline","content":[{"type":"text","text":"class"}]},{"type":"text","text":"文件的常量池中的表現形式是"},{"type":"codeinline","content":[{"type":"text","text":"123123"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"\"123\" + 456"}]},{"type":"text","text":"這個表達式在"},{"type":"codeinline","content":[{"type":"text","text":"class"}]},{"type":"text","text":"文件的常量池中的表現形式是"},{"type":"codeinline","content":[{"type":"text","text":"123456"}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"值相同的"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"或者"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"的常量池中只會存在一個常量項("},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_String"}]},{"type":"text","text":"類型和"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Utf8"}]},{"type":"text","text":"都只有一項)。例如上面源代碼中,雖然聲明瞭兩個常量值分別爲"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"\"123\" + 456"}]},{"type":"text","text":",但是最後"},{"type":"codeinline","content":[{"type":"text","text":"class"}]},{"type":"text","text":"文件的常量池中只有一個值爲"},{"type":"codeinline","content":[{"type":"text","text":"123456"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Utf8"}]},{"type":"text","text":"常量項以及一個對應的"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_String"}]},{"type":"text","text":"常量項。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"2. 類加載"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"text","text":"運行時,加載"},{"type":"codeinline","content":[{"type":"text","text":"Main"}]},{"type":"text","text":"類時,"},{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"text","text":"會根據 "},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"的常量池 創建 "},{"type":"codeinline","content":[{"type":"text","text":"運行時常量池"}]},{"type":"text","text":", "},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"的常量池 中的內容會在類加載時進入方法區的 "},{"type":"codeinline","content":[{"type":"text","text":"運行時常量池"}]},{"type":"text","text":"。對於"},{"type":"codeinline","content":[{"type":"text","text":"class文件"}]},{"type":"text","text":"的常量池中的符號引用,會在類加載的"},{"type":"codeinline","content":[{"type":"text","text":"解析(resolve)階段"}]},{"type":"text","text":",會將其轉化爲真正的值。但在"},{"type":"codeinline","content":[{"type":"text","text":"HotSpot"}]},{"type":"text","text":"中,符號引用的"},{"type":"codeinline","content":[{"type":"text","text":"解析"}]},{"type":"text","text":"並不一定是在類加載時立即執行的,而是推遲到第一次執行相關指令(即引用了符號引用的指令,"},{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3","title":""},"content":[{"type":"text","text":"JLS - 5.4.3. Resolution"}]},{"type":"text","text":" )時纔會去真正進行解析,這就做"},{"type":"codeinline","content":[{"type":"text","text":"延遲解析"}]},{"type":"text","text":"/"},{"type":"codeinline","content":[{"type":"text","text":"惰性解析"}]},{"type":"text","text":"("},{"type":"codeinline","content":[{"type":"text","text":"\"lazy\" or \"late\" resolution"}]},{"type":"text","text":")。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於一些基本類型的常量項,例如"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Integer_info"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Float_info"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Long_info"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Double_info"}]},{"type":"text","text":",在類加載階段會將"},{"type":"codeinline","content":[{"type":"text","text":"class"}]},{"type":"text","text":"文件常量池中的值轉化爲"},{"type":"codeinline","content":[{"type":"text","text":"運行時常量池"}]},{"type":"text","text":"中的值,分別對應"},{"type":"codeinline","content":[{"type":"text","text":"C++"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"int"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"float"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"long"}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"double"}]},{"type":"text","text":"類型;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Utf8"}]},{"type":"text","text":"類型的常量項,在類加載的解析階段被轉化爲"},{"type":"codeinline","content":[{"type":"text","text":"Symbol"}]},{"type":"text","text":"對象("},{"type":"codeinline","content":[{"type":"text","text":"HotSpot VM"}]},{"type":"text","text":"層面的一個"},{"type":"codeinline","content":[{"type":"text","text":"C++"}]},{"type":"text","text":"對象)。同時"},{"type":"codeinline","content":[{"type":"text","text":"HotSpot"}]},{"type":"text","text":"使用"},{"type":"codeinline","content":[{"type":"text","text":"SymbolTable"}]},{"type":"text","text":"(結構與"},{"type":"codeinline","content":[{"type":"text","text":"StringTable"}]},{"type":"text","text":"類似)來緩存"},{"type":"codeinline","content":[{"type":"text","text":"Symbol"}]},{"type":"text","text":"對象,所以在類加載完成後,"},{"type":"codeinline","content":[{"type":"text","text":"SymbolTable"}]},{"type":"text","text":"中應該有所有的"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Utf8"}]},{"type":"text","text":"常量對應的"},{"type":"codeinline","content":[{"type":"text","text":"Symbol"}]},{"type":"text","text":"對象;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而對於"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_String"}]},{"type":"text","text":"類型的常量項,因爲其內容是一個符號引用(指向"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_Utf8"}]},{"type":"text","text":"類型常量的索引值),所以需要進行解析,在類加載的解析階段會將其轉化爲"},{"type":"codeinline","content":[{"type":"text","text":"java.lang.String"}]},{"type":"text","text":"對象對應的"},{"type":"codeinline","content":[{"type":"text","text":"oop"}]},{"type":"text","text":"(可以理解爲"},{"type":"codeinline","content":[{"type":"text","text":"Java"}]},{"type":"text","text":"對象在"},{"type":"codeinline","content":[{"type":"text","text":"HotSpot VM"}]},{"type":"text","text":"層面的表示),並使用"},{"type":"codeinline","content":[{"type":"text","text":"StringTable"}]},{"type":"text","text":"來進行緩存。但是"},{"type":"codeinline","content":[{"type":"text","text":"CONSTANT_String"}]},{"type":"text","text":"類型的常量,屬於上文提到的"},{"type":"codeinline","content":[{"type":"text","text":"延遲解析"}]},{"type":"text","text":"的範疇,也就是在類加載時並不會立即執行解析,而是等到第一次執行相關指令時(一般來說是"},{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令)纔會真正解析。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"3. 執行指令"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面提到,"},{"type":"codeinline","content":[{"type":"text","text":"JVM"}]},{"type":"text","text":"會在第一次執行相關指令的時候去執行真正的解析,對於上文給出的代碼,觀察字節碼可以發現,"},{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令中使用到了符號引用,所以在執行"},{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令時,需要進行解析操作。那麼"},{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令到底做了什麼呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令會從"},{"type":"codeinline","content":[{"type":"text","text":"運行時常量池"}]},{"type":"text","text":"中查找指定"},{"type":"codeinline","content":[{"type":"text","text":"index"}]},{"type":"text","text":"對應的常量項,並將其壓入棧中。如果該項還未解析,則需要先進行解析,將符號引用轉化爲具體的值,然後再將其壓入棧中。如果這個未解析的項是"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類型的常量,則先從"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中查找是否已經有了相同內容的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,如果有則直接將"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的該對象壓入棧中;如果沒有,則會創建一個新的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象加入"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中,並將創建的新對象壓入棧中。可見,如果代碼中聲明多個相同內容的"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":"或者"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量表達式"}]},{"type":"text","text":",那麼只會在第一次執行"},{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令時創建一個"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,後續相同的"},{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令執行時相應位置的常量已經解析過了,直接壓入棧中即可。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"總結一下:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"在編譯階段,源碼中"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"字符串字面量"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"或者"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"字符串常量表達式"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"轉化爲了"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"class文件"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"的常量池中的"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"CONSTANT_String"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"常量項。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"在類加載階段,"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"class文件"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"的"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"常量池"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"中的"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"CONSTANT_String"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"常量項被存入了"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"運行時常量池"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"中,但保存的內容仍然是一個符號引用,未進行解析。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"在指令執行階段,當第一次執行"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"ldc"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"指令時,"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"運行時常量池"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"中的"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"CONSTANT_String"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"項還未解析,會真正執行解析,解析過程中會創建"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"String"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"對象並加入"},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"strong"}],"text":"字符串"}],"marks":[{"type":"strong"}]},{"type":"text","marks":[{"type":"strong"}],"text":"常量池。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"緩存關鍵源碼分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到,其實"},{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令在解析"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"類型常量的時候與"},{"type":"codeinline","content":[{"type":"text","text":"String.intern()"}]},{"type":"text","text":"方法的邏輯很相似:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令中解析"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"常量:先從"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中查找是否有相同內容的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,如果有則將其壓入棧中,如果沒有,則創建新對象加入"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"並壓入棧中。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"String.intern()"}]},{"type":"text","text":"方法:先從"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中查找是否有相同內容的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,如果有則返回該對象引用,如果沒有,則將自身加入"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"並返回。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實際在"},{"type":"codeinline","content":[{"type":"text","text":"HotSpot"}]},{"type":"text","text":"內部實現上,"},{"type":"codeinline","content":[{"type":"text","text":"ldc"}]},{"type":"text","text":"指令 與 "},{"type":"codeinline","content":[{"type":"text","text":"String.intern()"}]},{"type":"text","text":"對應的"},{"type":"codeinline","content":[{"type":"text","text":"native"}]},{"type":"text","text":"方法 調用了相同的內部方法。我們以"},{"type":"codeinline","content":[{"type":"text","text":"OpenJDK 8"}]},{"type":"text","text":"的源代碼爲例,簡單分析一下其過程,代碼如下(源碼位置:"},{"type":"codeinline","content":[{"type":"text","text":"src/share/vm/classfile/SymbolTable.cpp"}]},{"type":"text","text":"):"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"\n// String.intern()方法會調用這個方法\n// 參數 \"oop string\"代表調用intern()方法的String對象\noop StringTable::intern(oop string, TRAPS)\n{\n if (string == NULL) return NULL;\n ResourceMark rm(THREAD);\n int length;\n Handle h_string (THREAD, string);\n jchar* chars = java_lang_String::as_unicode_string(string, length, CHECK_NULL); // 將String對象轉化爲字符序列\n oop result = intern(h_string, chars, length, CHECK_NULL);\n return result;\n}\n\n// ldc指令執行時會調用這個方法\n// 參數 \"Symbol* symbol\" 是 運行時常量池 中 ldc指令的參數(索引位置)對應位置的Symbol對象\noop StringTable::intern(Symbol* symbol, TRAPS) {\n if (symbol == NULL) return NULL;\n ResourceMark rm(THREAD);\n int length;\n jchar* chars = symbol->as_unicode(length); // 將Symbol對象轉化爲字符序列\n Handle string;\n oop result = intern(string, chars, length, CHECK_NULL);\n return result;\n}\n\n// 上面兩個方法都會調用這個方法\noop StringTable::intern(Handle string_or_null, jchar* name, int len, TRAPS) {\n // 嘗試從字符串常量池中尋找\n unsigned int hashValue = hash_string(name, len);\n int index = the_table()->hash_to_index(hashValue);\n oop found_string = the_table()->lookup(index, name, len, hashValue);\n\n // 如果找到了直接返回\n if (found_string != NULL) {\n ensure_string_alive(found_string);\n return found_string;\n }\n\n // ...... 省略部分代碼 ......\n \n Handle string;\n // 嘗試複用原字符串,如果無法複用,則會創建新字符串\n // JDK 6中這裏的實現有一些不同,只有string_or_null已經存在於永久代中才會複用\n if (!string_or_null.is_null()) {\n string = string_or_null;\n } else {\n string = java_lang_String::create_from_unicode(name, len, CHECK_NULL);\n }\n\n //...... 省略部分代碼 ......\n\n oop added_or_found;\n {\n MutexLocker ml(StringTable_lock, THREAD);\n // 添加字符串到 StringTable 中\n added_or_found = the_table()->basic_add(index, string, name, len,\n hashValue, CHECK_NULL);\n }\n ensure_string_alive(added_or_found);\n return added_or_found;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"案例分析"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"說明"},{"type":"text","text":":因爲在"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"之後"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"從"},{"type":"codeinline","content":[{"type":"text","text":"永久代"}]},{"type":"text","text":"移到了"},{"type":"codeinline","content":[{"type":"text","text":"堆"}]},{"type":"text","text":"中,可能在一些代碼上"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"與之後的版本表現不一致。所以下面的代碼都使用"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"Java 7"}]},{"type":"text","text":"分別進行測試,如果未特殊說明,表示在兩個版本上結果相同,如果不同,會單獨指出。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"final int a = 4;\nint b = 4;\nString s1 = \"123\" + a + \"567\";\nString s2 = \"123\" + b + \"567\";\nString s3 = \"1234567\";\nSystem.out.println(s1 == s2);\nSystem.out.println(s1 == s3);\nSystem.out.println(s2 == s3);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"結果:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"false\ntrue\nfalse"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解釋:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"第三行,因爲"},{"type":"codeinline","content":[{"type":"text","text":"a"}]},{"type":"text","text":"被定義爲常量,所以"},{"type":"codeinline","content":[{"type":"text","text":"\"123\" + a + \"567\""}]},{"type":"text","text":"是一個"},{"type":"codeinline","content":[{"type":"text","text":"常量表達式"}]},{"type":"text","text":",在編譯期會被編譯爲"},{"type":"codeinline","content":[{"type":"text","text":"\"1234567\""}]},{"type":"text","text":",所以會在"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中創建"},{"type":"codeinline","content":[{"type":"text","text":"\"1234567\""}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"s1"}]},{"type":"text","text":"指向"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"\"1234567\""}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"第四行,"},{"type":"codeinline","content":[{"type":"text","text":"b"}]},{"type":"text","text":"被定義爲變量,"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"\"567\""}]},{"type":"text","text":"是"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":",所以首先在"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中創建"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"\"567\""}]},{"type":"text","text":",然後通過"},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":"隱式拼接在堆中創建"},{"type":"codeinline","content":[{"type":"text","text":"\"1234567\""}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"s2"}]},{"type":"text","text":"指向堆中的"},{"type":"codeinline","content":[{"type":"text","text":"\"1234567\""}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"第五行,"},{"type":"codeinline","content":[{"type":"text","text":"\"1234567\""}]},{"type":"text","text":"是一個"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":",因爲此時"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中已經存在了"},{"type":"codeinline","content":[{"type":"text","text":"\"1234567\""}]},{"type":"text","text":",所以"},{"type":"codeinline","content":[{"type":"text","text":"s3"}]},{"type":"text","text":"指向字符串"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"\"1234567\""}]},{"type":"text","text":"。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String s1 = new String(\"123\");\nString s2 = s1.intern();\nString s3 = \"123\";\nSystem.out.println(s1 == s2); \nSystem.out.println(s1 == s3); \nSystem.out.println(s2 == s3);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"結果:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"false\nfalse\ntrue"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解釋:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"第一行,"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"是一個"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":",所以首先在"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中創建了一個"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"對象,然後使用"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"的構造函數在堆中創建了一個"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"對象,"},{"type":"codeinline","content":[{"type":"text","text":"s1"}]},{"type":"text","text":"指向堆中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"第二行,因爲"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中已經有了"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":",所以"},{"type":"codeinline","content":[{"type":"text","text":"s2"}]},{"type":"text","text":"指向"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"第三行,同樣因爲"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中已經有了"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":",所以"},{"type":"codeinline","content":[{"type":"text","text":"s3"}]},{"type":"text","text":"指向"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String s1 = String.valueOf(\"123\");\nString s2 = s1.intern();\nString s3 = \"123\";\nSystem.out.println(s1 == s2); \nSystem.out.println(s1 == s3); \nSystem.out.println(s2 == s3); "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"結果:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"true\ntrue\ntrue"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解釋:與上一種情況的區別在於,"},{"type":"codeinline","content":[{"type":"text","text":"String.valueOf()"}]},{"type":"text","text":"方法在參數爲"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象的時候會直接將參數作爲返回值,不會在堆上創建新對象,所以"},{"type":"codeinline","content":[{"type":"text","text":"s1"}]},{"type":"text","text":"也指向"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":",三個變量指向同一個對象。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String s1 = new String(\"123\") + new String(\"456\"); \nString s2 = s1.intern();\nString s3 = \"123456\";\nSystem.out.println(s1 == s2); \nSystem.out.println(s1 == s3); \nSystem.out.println(s2 == s3);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面的代碼在"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"Java 7"}]},{"type":"text","text":"中結果是不同的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"中:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"false\nfalse\ntrue"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解釋:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"第一行,"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"\"456\""}]},{"type":"text","text":"是"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":",所以首先在"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中創建"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"\"456\""}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"+"}]},{"type":"text","text":"操作符通過"},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":"隱式拼接在堆中創建"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"s1"}]},{"type":"text","text":"指向堆中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"第二行,將"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"緩存到"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中,因爲"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"中"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的對象是在永久代創建的,所以會在"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"(永久代)創建一個"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":",此時在堆中和永久代中各有一個"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"s2"}]},{"type":"text","text":"指向"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"(永久代)中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"第三行,"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"是"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":",因爲此時"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"(永久代)中已經存在"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":",所以"},{"type":"codeinline","content":[{"type":"text","text":"s3"}]},{"type":"text","text":"指向"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"(永久代)中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在"},{"type":"codeinline","content":[{"type":"text","text":"Java 7"}]},{"type":"text","text":"中:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"true\ntrue\ntrue"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解釋:與"},{"type":"codeinline","content":[{"type":"text","text":"Java 6"}]},{"type":"text","text":"的區別在於,因爲"},{"type":"codeinline","content":[{"type":"text","text":"Java 7"}]},{"type":"text","text":"中"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的對象是在"},{"type":"codeinline","content":[{"type":"text","text":"堆"}]},{"type":"text","text":"上創建的,所以當執行第二行"},{"type":"codeinline","content":[{"type":"text","text":"String s2 = s1.intern();"}]},{"type":"text","text":"時不會再創建新的"},{"type":"codeinline","content":[{"type":"text","text":"String"}]},{"type":"text","text":"對象,而是直接將"},{"type":"codeinline","content":[{"type":"text","text":"s1"}]},{"type":"text","text":"的引用添加到"},{"type":"codeinline","content":[{"type":"text","text":"StringTable"}]},{"type":"text","text":"中,所以三個對象都指向常量池中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":",也就是第一行中在堆中創建的對象。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Java 7"}]},{"type":"text","text":"下,"},{"type":"codeinline","content":[{"type":"text","text":"s1 == s2"}]},{"type":"text","text":"結果爲"},{"type":"codeinline","content":[{"type":"text","text":"true"}]},{"type":"text","text":"也能夠用來佐證我們上面"},{"type":"codeinline","content":[{"type":"text","text":"延遲解析"}]},{"type":"text","text":"的過程。我們假設如果"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"不是延遲解析的,而是類加載的時候解析完成並進入常量池的,"},{"type":"codeinline","content":[{"type":"text","text":"s1.intern()"}]},{"type":"text","text":"的返回值應該是常量池中存在的"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":",而不會將"},{"type":"codeinline","content":[{"type":"text","text":"s1"}]},{"type":"text","text":"指向的堆中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"對象加入常量池,所以結果應該是"},{"type":"codeinline","content":[{"type":"text","text":"s2"}]},{"type":"text","text":"不等於"},{"type":"codeinline","content":[{"type":"text","text":"s1"}]},{"type":"text","text":"而等於"},{"type":"codeinline","content":[{"type":"text","text":"s3"}]},{"type":"text","text":"。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"String s1 = new String(\"123\") + new String(\"456\");\nString s2 = \"123456\";\nString s3 = s1.intern();\nSystem.out.println(s1 == s2); \nSystem.out.println(s1 == s3); \nSystem.out.println(s2 == s3);"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"結果:"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"false\nfalse\ntrue"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解釋:"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"第一行,"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"\"456\""}]},{"type":"text","text":"是"},{"type":"codeinline","content":[{"type":"text","text":"字符串字面量"}]},{"type":"text","text":",所以首先在"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中創建"},{"type":"codeinline","content":[{"type":"text","text":"\"123\""}]},{"type":"text","text":"和"},{"type":"codeinline","content":[{"type":"text","text":"\"456\""}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"+"}]},{"type":"text","text":"操作符通過"},{"type":"codeinline","content":[{"type":"text","text":"StringBuilder"}]},{"type":"text","text":"隱式拼接在堆中創建"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":","},{"type":"codeinline","content":[{"type":"text","text":"s1"}]},{"type":"text","text":"指向堆中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"第二行,"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"是字符串字面量,此時字符串常量池中不存在"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":",所以在"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中創建"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":", "},{"type":"codeinline","content":[{"type":"text","text":"s2"}]},{"type":"text","text":"指向"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":";"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"第三行,因爲此時字符串常量池中已經存在"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":",所以"},{"type":"codeinline","content":[{"type":"text","text":"s3"}]},{"type":"text","text":"指向"},{"type":"codeinline","content":[{"type":"text","text":"字符串常量池"}]},{"type":"text","text":"中的"},{"type":"codeinline","content":[{"type":"text","text":"\"123456\""}]},{"type":"text","text":"。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"參考"}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.geeksforgeeks.org/java-substring-method-memory-leak-issue-and-fix/","title":""},"content":[{"type":"text","text":"Java substring() method memory leak issue and fix"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://stackoverflow.com/questions/15612157/substring-method-in-string-class-causes-memory-leak","title":""},"content":[{"type":"text","text":"java - substring method in String class causes memory leak - Stack Overflow"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5","title":""},"content":[{"type":"text","text":"JLS - 3.10.5. String Literals"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28","title":""},"content":[{"type":"text","text":"JLS - 15.28 Constant Expressions"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://java-performance.info/string-intern-in-java-6-7-8/","title":""},"content":[{"type":"text","text":"String.intern in Java 6, 7 and 8 – string pooling"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.zhihu.com/question/55994121/answer/147296098","title":""},"content":[{"type":"text","text":"(Java 中new String(\"字面量\") 中 \"字面量\" 是何時進入字符串常量池的? - 木女孩的回答 - 知乎"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":7,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://tech.meituan.com/2014/03/06/in-depth-understanding-string-intern.html","title":""},"content":[{"type":"text","text":"深入解析String#intern"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":8,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3","title":""},"content":[{"type":"text","text":"JLS - 5.4.3. Resolution"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":9,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.iteye.com/blog/rednaxelafx-774673","title":""},"content":[{"type":"text","text":"請別再拿“String s = new String(\"xyz\");創建了多少個String實例”來面試了吧"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":10,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://blog.jamesdbloom.com/JVMInternals.html","title":""},"content":[{"type":"text","text":"JVM Internals"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":11,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://wu-sheng.github.io/me/articles/JVMInternals","title":""},"content":[{"type":"text","text":"探祕JVM內部結構(翻譯)"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":12,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://blog.csdn.net/u010349169/category_9263262.html","title":""},"content":[{"type":"text","text":"Java虛擬機原理圖解"}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章