1. 程式人生 > >Java9後String的空間優化

Java9後String的空間優化

byte[] 存儲 表示 它的 [] 設置 () final 開發

據我所知 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的空間優化