Java高級面試 —— Java String可以有多長?

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é)果往往涉及很多重要的知識理解。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容