標籤:strong turn 中文字元 大量 指定 兩種 關注 它的 預設
據我所知 Java 開發人員幾乎任何時候都會想到 String,字串確實已經成為最常用的類了,而且是大量使用。我們都知道,String 其實是封裝了字元,裡面必須由字元或位元組數組來存放,從 Java9 開始 Java 語言開發人員對 String 做了一些空間的最佳化。
從char到byte
JDK9 之前的庫的 String 類的實現使用了 char 數組來存放字串,char 佔用16位,即兩位元組。
private final char value[];
這種情況下,如果我們要儲存字元 A ,則為 0x00 0x41 ,此時前面的一個位元組空間浪費了。但如果儲存中文字元則不存在浪費的情況,也就是說如果儲存 ISO-8859-1 編碼內的字元則浪費,之外的字元則不會浪費。
而 JDK9 後 String 類的實現使用了 byte 數組存放字串,每個 byte 佔用8位,即1位元組。
private final byte[] value
編碼
String 支援多種編碼,但如果不指定編碼的話,它可能使用兩種編碼,分別為 LATIN1 和 UTF16。LATIN1 可能比較陌生,其實就是 ISO-8859-1 編碼,屬於單位元組編碼。而 UTF16 為雙位元組編碼,它使用1個或2個16位長的空間儲存。
壓縮空間
壓縮的字元對象主要是在 ISO-8859-1 編碼內的字元,比如英語字母數字還有其他常見符號。為了更好理解我們看,假如我們有一個“what”字串,那麼如果在 Java9 之前,它的儲存是按如下隊列排列的,可以看到每個字元都需要16位來儲存,而高位元組位都為0,這個其實就是浪費了。
Java9後String的空間最佳化
而在 Java9 後,它的儲存的排列則很緊湊了,如,只需四個位元組即可。
Java9後String的空間最佳化
但如果是“哈a”,則布局為,所以如果字串中的字元一旦包含了不在 ISO-8859-1 編碼內的字元,則同樣還是統一使用16位長度來儲存。
Java9後String的空間最佳化
Java9 的 String 預設是使用了上述緊湊的空間布局的,看如下代碼,預設將 COMPACT_STRINGS 設定為 true。而如果要取消緊湊的布局可以通過配置 VM 參數 -XX:-CompactStrings 實現。
static final boolean COMPACT_STRINGS;
static {
COMPACT_STRINGS = true;
}
字串長度
因為改變了 String 的實現,使用了 UTF-16 或 LATIN-1 編碼,所以內部需要一個標識 coder 來表示使用了哪種編碼,LATIN1 值為0,UTF16 值為1。
private final byte coder;
static final byte LATIN1 = 0;
static final byte UTF16 = 1;
而字串的長度也與編碼相關,計算時通過右移來實現。如果是 LATIN-1 編碼,則右移0位,數組長度即為字串長度。而如果是 UTF16 編碼,則右移1位,數組長度的二分之一為字串長度。
public int length() {
return value.length >> coder();
}
總結
字串對象是 Java 中大量使用的對象,而且我們會輕易大量使用它而從不考慮它的代價,所以對其的空間最佳化是有必要的,Java9 開始對 這能協助我們減少字串在堆中佔用的空間,而且還能減輕GC壓力。同時也能看到該空間最佳化對中文來說意義不大。
喜歡的點點關注,點點贊。
Java9後String的空間最佳化