1. 題目剖析
Java String可以有多長(zhǎng)?相信大部分人不會(huì)太關(guān)注這個(gè)問題话瞧,甚至可能有些人會(huì)認(rèn)為String要多長(zhǎng)可以有多長(zhǎng)嫩与,很明顯這是不實(shí)際的想法。假設(shè)現(xiàn)在有這樣一個(gè)場(chǎng)景:
byte[] jsonBytes = readTaskFromFile();
String json = new String(jsonBytes);
Task entity = new Gson().fromJson(json, Task.class);
這段代碼看似沒什么問題交排,但是一旦文件存儲(chǔ)內(nèi)容的字節(jié)長(zhǎng)度超過String運(yùn)行時(shí)所能承受的長(zhǎng)度划滋,這里的json就不是一個(gè)完整的json字符串埃篓,這樣在使用gson做反序列化時(shí)架专,必然會(huì)因?yàn)閖son格式不正確導(dǎo)致反序列化失敗,拋出異常案狠。
2. 問題拆分
2.1 String可容納的字節(jié)有多少?
當(dāng)我們?cè)诜椒ɡ镎{(diào)用場(chǎng)景里的代碼是灿椅,其臨時(shí)變量是存儲(chǔ)在
Java堆
中的,String類型的長(zhǎng)度理論上取決于傳入的byte數(shù)組的長(zhǎng)度。
在創(chuàng)建byte數(shù)組時(shí),要求new []傳入的必須是一個(gè)整型類型的數(shù)據(jù),也就是說byte[]數(shù)組的最大長(zhǎng)度為Integer.MAX_VALUE
,但是,我們從ArrayList的源碼可以看出,數(shù)組可分配的最大長(zhǎng)度應(yīng)該是Integer.MAX_VALUE - 8
,否則會(huì)拋出OutOfMemoryError: Requested array size exceeds VM limit
錯(cuò)誤:
/**
* 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];
還會(huì)拋出錯(cuò)誤java.lang.OutOfMemoryError: Java heap space
,那是受到了Java堆可分配的內(nèi)存大小限制并徘,如何在編譯器里修改Java虛擬機(jī)堆棧的大小,這里就不多說扰魂,主要是想說明其實(shí)還有這樣一個(gè)限制因素存在麦乞。
當(dāng)String變量是一個(gè)類中的全局變量時(shí),其變量是存在在Java方法區(qū)里的劝评,這時(shí)String類型可存儲(chǔ)的字節(jié)長(zhǎng)度取決于.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)去存儲(chǔ)的:
CONSTANT_Utf8_info {
u1 tag;
u2 length; // 0 ~ 65535
u1 bytes[length];
}
u2是表示一個(gè)2個(gè)字節(jié)的數(shù)據(jù)類型蒋畜,這也就意味著允許的最大長(zhǎng)度為65535声畏。
2.2 String可容納的字符數(shù)有多少?
前面我們都是從String可存儲(chǔ)的字節(jié)數(shù)去考慮的百侧,現(xiàn)在從可存儲(chǔ)的字符數(shù)去考慮砰识,假如字符是以u(píng)tf-8編碼的能扒,其實(shí)這個(gè)問題可以直接轉(zhuǎn)換成:
一個(gè)字符使用utf-8編碼對(duì)應(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 | 表情符號(hào) |
所以,如果一個(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ǔ)深厚外,還希望你對(duì)Java虛擬機(jī)對(duì)類型的存儲(chǔ)有一定的了解测摔,另外就是希望從你的回答中置济,看出你有積極的探索欲望。有時(shí)候锋八,往往看似簡(jiǎn)單的提問浙于,其期待的結(jié)果往往涉及很多重要的知識(shí)理解。