1.String
String類的基本字段(field)
Java9之后,String中用byte[]存儲字符串,并用coder表示該字符串使用哪種編碼。
coder主要是為了適應不同語言字符的需要,有的字符需要2字節編碼,有的只需要1字節,coder就表示這個字符串應當使用哪種編碼規則。這樣在存儲像英文一樣只需要一個字節的字符時,可以壓縮空間。coder有LATIN1(1字節)和UTF16(2字節)兩種選項,相關的還有COMPACT_STRINGS,為true表示這個字符串是壓縮的。編碼這塊由JVM處理。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final byte[] value;
/** The identifier of the encoding used to encode the bytes in {@code value}. */
private final byte coder;
static final boolean COMPACT_STRINGS;
static {
COMPACT_STRINGS = true;
}
/** Cache the hash code for the string */
private int hash; // Default to 0
}
不可變的String
String類是final的,存儲的byte[]也是final的,所以保證String不可變。
不可變的好處
- 可以緩存hash值
- String Pool 的需要
- 幫助其他Objects的使用
- 例如Set<String>中,如果String可變,改變后的String可能違反set規則
- 安全性
- 例如在作為網絡連接參數時,保證String不可變更具安全性
- 線程安全
構造函數
在將一個字符串對象作為另一個字符串對象的構造函數參數時,并不會完全復制 value 數組內容,而是都會指向同一個 value 數組
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
2. StringBuilder和StringBuffer
和String一樣用byte[]存儲,也有coder成員。但是這兩個都是可變的,類內部提供append()之類的修改字符串的方法。
二者都繼承自AbstractStringBuilder,其實相差不大,主要是StringBuffer中很多方法都被關鍵字synchronized
修飾,因此StringBuffer是線程安全的,而StringBuilder是線程不安全的。也因此,但單線程的情況下, StringBuilder的性能要比StringBuffer更好。
如果要對一個字符串做頻繁修改,最好用StringBuilder,如果是在多線程的情況下(變量可能被多個線程訪問),最好用StringBuffer。
3. StringPool 字符串常量池
String Pool保存著所有字符串字面量(literal strings),這些字面量在編譯時期就確定。可以使用 String 的 intern() 方法在運行過程中將字符串添加到 String Pool 中。
intern()
當一個字符串調用 intern() 方法時,如果 String Pool 中已經存在一個字符串和該字符串值相等(使用 equals() 方法進行確定),那么就會返回 String Pool 中字符串的引用;否則,就會在 String Pool 中添加一個新的字符串,并返回這個新字符串的引用。
String s1 = "hello"; //用字面量創建字符串,會自動將字符串放入 String Pool 中
String s2 = s1.intern(); //返回的是常量池中"Hello"字符串的引用
String Pool是一個固定大小的Hashtable,默認值大小長度是1009,如果放進String Pool的String非常多,就會造成Hash沖突嚴重,從而導致鏈表會很長,而鏈表長了后直接會造成的影響就是當調用 String.intern() 時性能會大幅下降。在jdk7中,StringTable的長度可以通過一個參數指定:XX:StringTableSize=99991