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

1. 題目剖析

Java String可以有多長?相信大部分人不會太關注這個問題,甚至可能有些人會認爲String要多長可以有多長,很明顯這是不實際的想法。假設現在有這樣一個場景:

   byte[] jsonBytes = readTaskFromFile();
   String json = new String(jsonBytes);
   Task entity = new Gson().fromJson(json, Task.class);

這段代碼看似沒什麼問題,但是一旦文件存儲內容的字節長度超過String運行時所能承受的長度,這裏的json就不是一個完整的json字符串,這樣在使用gson做反序列化時,必然會因爲json格式不正確導致反序列化失敗,拋出異常。

2. 問題拆分

2.1 String可容納的字節有多少?

當我們在方法裏調用場景裏的代碼是,其臨時變量是存儲在Java堆中的,String類型的長度理論上取決於傳入的byte數組的長度。

在創建byte數組時,要求new []傳入的必須是一個整型類型的數據,也就是說byte[]數組的最大長度爲Integer.MAX_VALUE,但是,我們從ArrayList的源碼可以看出,數組可分配的最大長度應該是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;

但是實際上,如果真的執行了下面的代碼:

   byte[] bytes = new byte[Integer.MAX_VALUE - 8];

還會拋出錯誤java.lang.OutOfMemoryError: Java heap space,那是受到了Java堆可分配的內存大小限制,如何在編譯器裏修改Java虛擬機堆棧的大小,這裏就不多說,主要是想說明其實還有這樣一個限制因素存在。

當String變量是一個類中的全局變量時,其變量是存在在Java方法區裏的,這時String類型可存儲的字節長度取決於.class描述全局String類型變量的數據結構。

例如:

   private final static String LONG_STRING = "aaaa.....";

當.java文件編譯成.class文件時,其類中的靜態String數據是以以下數據結構去存儲的:

   CONSTANT_Utf8_info {
       u1 tag;
       u2 length;   // 0 ~ 65535
       u1 bytes[length];
   }

u2是表示一個2個字節的數據類型,這也就意味着允許的最大長度爲65535。

2.2 String可容納的字符數有多少?

前面我們都是從String可存儲的字節數去考慮的,現在從可存儲的字符數去考慮,假如字符是以utf-8編碼的,其實這個問題可以直接轉換成:

一個字符使用utf-8編碼對應多少個字節數?

Unicode bit數 UTF-8 byte數 常見字符類型
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 表情符號

所以,如果一個String類型可容納的字符數,應該是這樣的:

字符類型 在Java棧中的大小 在Java堆中的大小
Latin字母 65535 Integer.MAX_VALUE - 8
中文 65535 / 3 (Integer.MAX_VALUE - 8) / 3

拓展問題,String.length()返回的是字節數還是字符數?答案是字節數。

3. 總結

面試官問這個問題時,是希望你除了Java基礎深厚外,還希望你對Java虛擬機對類型的存儲有一定的瞭解,另外就是希望從你的回答中,看出你有積極的探索慾望。有時候,往往看似簡單的提問,其期待的結果往往涉及很多重要的知識理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章