1. 程式人生 > >String字串的最大長度是多少?

String字串的最大長度是多少?

在學習和開發過程中,我們經常會討論 short ,int 和 long 這些基本資料型別的取值範圍,但是對於 String 型別我們好像很少注意它的“取值範圍”。那麼對於 String 型別,它到底有沒有長度限制呢? 其實 String 型別的物件,他們是有長度限制的, String 物件並不能“儲存”無限長度的字串。關於 String 的長度限制要從**編譯時限制**和**執行時限制**兩方面考慮。 ## 編譯期限制 有JVM虛擬機器相關知識的同學肯定知道,下面定義的字串常量“自由之路”會被放入方法區的常量池中。 ```java String s = "自由之路"; System.out.println(s); ``` Stirng 長度之所以會受限制,是因JVM規範對常量池有所限制。常量池中的每一種資料項都有自己的型別。Java中的UTF-8編碼的Unicode字串在常量池中以CONSTANT_Utf8型別表示。 CONSTANT_Utf8的資料結構如下: ``` CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; } ``` 我們重點關注下長度為 length 的那個bytes陣列,這個陣列就是真正儲存常量資料的地方,而 length 就是陣列可以儲存的最大位元組數。length 的型別是u2,u2是無符號的16位整數,因此理論上允許的的最大長度是2^16-1=65535。所以上面byte陣列的最大長度可以是65535。 ```java //65535個d,編譯報錯 String s = "dd..dd"; //65534個d,編譯通過 String s1 = "dd..d"; ``` 上面的列子中長度為65535的字串s還是編譯失敗了,但是長度為65534的字串 s1 編譯是成功的。這個好像和我們剛剛的結論不符合。 其實,這時Javac編譯器的額外限制。在Javac的原始碼中可以找到以下程式碼: ```java private void checkStringConstant(DiagnosticPosition var1, Object var2) { if (this.nerrs == 0 && var2 != null && var2 instanceof String && ((String)var2).length() >= 65535) { this.log.error(var1, "limit.string", new Object[0]); ++this.nerrs; } } ``` 程式碼中可以看出,當引數型別為String,並且長度大於等於65535的時候,就會導致編譯失敗。 這裡需要重點強調下的是:String 的限制並不是對字串長度的限制,而是對字串底層儲存的限制。這句話可能比較抽象,下面舉個列子就清楚了。 Java中的字元常量都是使用UTF8編碼的,UTF8編碼使用1~4個位元組來表示具體的Unicode字元。所以有的字元佔用一個位元組,而我們平時所用的大部分中文都需要3個位元組來儲存。 ```java //65534個字母,編譯通過 String s1 = "dd..d"; //21845箇中文”自“,編譯通過 String s2 = "自自...自"; //一個英文字母d加上21845箇中文”自“,編譯失敗 String s3 = "d自自...自"; ``` 對於s1,一個字母d的UTF8編碼佔用一個位元組,65534字母佔用65534個位元組,長度是65534,也沒超過Javac的限制,所以可以編譯通過。 對於s2,一箇中文佔用3個位元組,21845個正好佔用65535個位元組,而且字串長度是21845,並沒有超過javac對長度的限制,所以可以編譯通過。 對於s3,一個英文字母d加上21845箇中文”自“佔用65535個位元組,超過了最常限制,編譯失敗。 ## 執行時限制 String 執行時的限制主要體現在 String 的建構函式上。下面是 String 的一個建構函式: ```java public String(char value[], int offset, int count) { ... } ``` 上面的count值就是字串的最大長度。在Java中,int的最大長度是2^31-1。所以在執行時,String 的最大長度是2^31-1。 但是這個也是理論上的長度,實際的長度還要看你JVM的記憶體。我們來看下,最大的字串會佔用多大的記憶體。 ``` (2^31-1)*2*16/8/1024/1024/1024 = 4GB ``` 所以在最壞的情況下,一個最大的字串要佔用4GB的記憶體。如果你的虛擬機器不能分配這麼多記憶體的話,會直接報錯的。 JDK9以後對String的儲存進行了優化。底層不再使用char陣列儲存字串,而是使用byte陣列。對於LATIN1字元的字串可以節省一倍的記憶體空間。 ## 簡單總結 String 的長度是有限制的。 - 編譯期的限制:字串的UTF8編碼值的位元組數不能超過65535,字串的長度不能超過65534; - 執行時限制:字串的長度不能超過2^31-1,佔用的記憶體數不能超過虛擬機器能夠提供的最大值。 ## 公眾號推薦 歡迎大家關注我的微信公眾號「程式設計師自由之路」 ![](https://img2020.cnblogs.com/blog/1775037/202005/1775037-20200505091245079-5446058