1. 題目剖析
Java String可以有多長?相信大部分人不會太關(guān)注這個(gè)問題,甚至可能有些人會認(rèn)為String要多長可以有多長,很明顯這是不實(shí)際的想法。假設(shè)現(xiàn)在有這樣一個(gè)場景:
byte[] jsonBytes = readTaskFromFile();
String json = new String(jsonBytes);
Task entity = new Gson().fromJson(json, Task.class);
這段代碼看似沒什么問題,但是一旦文件存儲內(nèi)容的字節(jié)長度超過String運(yùn)行時(shí)所能承受的長度,這里的json就不是一個(gè)完整的json字符串,這樣在使用gson做反序列化時(shí),必然會因?yàn)閖son格式不正確導(dǎo)致反序列化失敗,拋出異常。
2. 問題拆分
2.1 String可容納的字節(jié)有多少?
當(dāng)我們在方法里調(diào)用場景里的代碼是,其臨時(shí)變量是存儲在
Java堆中的,String類型的長度理論上取決于傳入的byte數(shù)組的長度。
在創(chuàng)建byte數(shù)組時(shí),要求new []傳入的必須是一個(gè)整型類型的數(shù)據(jù),也就是說byte[]數(shù)組的最大長度為Integer.MAX_VALUE,但是,我們從ArrayList的源碼可以看出,數(shù)組可分配的最大長度應(yīng)該是Integer.MAX_VALUE - 8,否則會拋出OutOfMemoryError: Requested array size exceeds VM limit錯誤:
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
但是實(shí)際上,如果真的執(zhí)行了下面的代碼:
byte[] bytes = new byte[Integer.MAX_VALUE - 8];
還會拋出錯誤java.lang.OutOfMemoryError: Java heap space,那是受到了Java堆可分配的內(nèi)存大小限制,如何在編譯器里修改Java虛擬機(jī)堆棧的大小,這里就不多說,主要是想說明其實(shí)還有這樣一個(gè)限制因素存在。
當(dāng)String變量是一個(gè)類中的全局變量時(shí),其變量是存在在Java方法區(qū)里的,這時(shí)String類型可存儲的字節(jié)長度取決于.class描述全局String類型變量的數(shù)據(jù)結(jié)構(gòu)。
例如:
private final static String LONG_STRING = "aaaa.....";
當(dāng).java文件編譯成.class文件時(shí),其類中的靜態(tài)String數(shù)據(jù)是以以下數(shù)據(jù)結(jié)構(gòu)去存儲的:
CONSTANT_Utf8_info {
u1 tag;
u2 length; // 0 ~ 65535
u1 bytes[length];
}
u2是表示一個(gè)2個(gè)字節(jié)的數(shù)據(jù)類型,這也就意味著允許的最大長度為65535。
2.2 String可容納的字符數(shù)有多少?
前面我們都是從String可存儲的字節(jié)數(shù)去考慮的,現(xiàn)在從可存儲的字符數(shù)去考慮,假如字符是以utf-8編碼的,其實(shí)這個(gè)問題可以直接轉(zhuǎn)換成:
一個(gè)字符使用utf-8編碼對應(yīng)多少個(gè)字節(jié)數(shù)?
| Unicode | bit數(shù) | UTF-8 | byte數(shù) | 常見字符類型 |
|---|---|---|---|---|
| 0000 ~ 007F | 0~7 | 0XXX XXXX | 1 | 拉丁字母 |
| 0080 ~07FF | 8~11 | 110X XXXX、10XX XXXX | 2 | |
| 0800 ~FFFF | 12~16 | 1110XXXX、10XX XXXX、10XX XXXX | 3 | 中文字符 |
| 1 0000 ~ 1F FFFF | 17~21 | 1111 0XXX、10XX XXXX、10XX XXXX、10XX XXXX | 4 | 表情符號 |
所以,如果一個(gè)String類型可容納的字符數(shù),應(yīng)該是這樣的:
| 字符類型 | 在Java棧中的大小 | 在Java堆中的大小 |
|---|---|---|
| Latin字母 | 65535 | Integer.MAX_VALUE - 8 |
| 中文 | 65535 / 3 | (Integer.MAX_VALUE - 8) / 3 |
3. 總結(jié)
面試官問這個(gè)問題時(shí),是希望你除了Java基礎(chǔ)深厚外,還希望你對Java虛擬機(jī)對類型的存儲有一定的了解,另外就是希望從你的回答中,看出你有積極的探索欲望。有時(shí)候,往往看似簡單的提問,其期待的結(jié)果往往涉及很多重要的知識理解。