據我所知 Java 開發人員幾乎任什麼時候候都會想到 String,字符串確實已經成爲最經常使用的類了,並且是大量使用。咱們都知道,String 實際上是封裝了字符,裏面必須由字符或字節數組來存放,從 Java9 開始 Java 語言開發者對 String 作了一些空間的優化。數組
JDK9 以前的庫的 String 類的實現使用了 char 數組來存放字符串,char 佔用16位,即兩字節。bash
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 後,它的存儲的排列則很緊湊了,以下圖,只需四個字節便可。學習
但若是是「哈a」,則佈局爲下圖,因此若是字符串中的字符一旦包含了不在 ISO-8859-1 編碼內的字符,則一樣仍是統一使用16位長度來保存。優化
Java9 的 String 默認是使用了上述緊湊的空間佈局的,看以下代碼,默認將 COMPACT_STRINGS 設置爲 true。而若是要取消緊湊的佈局能夠經過配置 VM 參數-XX:-CompactStrings
實現。ui
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壓力。同時也能看到該空間優化對中文來講意義不大。
-------------推薦閱讀------------
跟我交流,向我提問:
公衆號的菜單已分爲「讀書總結」、「分佈式」、「機器學習」、「深度學習」、「NLP」、「Java深度」、「Java併發核心」、「JDK源碼」、「Tomcat內核」等,可能有一款適合你的胃口。
歡迎關注: