作者:念念清晰
連結:https://juejin.cn/post/7343883765540831283
首先String的length方法返回是int。
所以理論上長度一定不會超過int的最大值。
編譯器源碼如下,限制了字串長度大於等於65535就會編譯不透過
privatevoid checkStringConstant(DiagnosticPosition var1, Object var2) {
if (this.nerrs == 0 && var2 != null && var2 instanceofString && ((String)var2).length() >= 65535) {
this.log.error(var1, "limit.string", newObject[0]);
++this.nerrs;
}
}
Java中的字元常量都是使用UTF8編碼的,UTF8編碼使用1~4個字節來表示具體的Unicode字元。所以有的字元占用一個字節,而我們平時所用的大部份中文都需要3個字節來儲存。
//65534個字母,編譯透過
String s1 = "dd..d";
//21845個中文」自「,編譯透過
String s2 = "自自...自";
//一個英文字母d加上21845個中文」自「,編譯失敗
String s3 = "d自自...自";
對於s1,一個字母d的UTF8編碼占用一個字節,65534字母占用65534個字節,長度是65534,長度和儲存都沒超過限制,所以可以編譯透過。
對於s2,一個中文占用3個字節,21845個正好占用65535個字節,而且字串長度是21845,長度和儲存也都沒超過限制,所以可以編譯透過。
對於s3,一個英文字母d加上21845個中文」自「占用65536個字節,超過了儲存最大限制,編譯失敗。
1.JVM規範對常量池有所限制。量池中的每一種數據項都有自己的型別。Java中的UTF-8編碼的Unicode字串在常量池中以CONSTANTUtf8型別表示。CONSTANTUtf8的數據結構如下:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
我們重點關註下長度為 length 的那個bytes陣列,這個陣列就是真正儲存常量數據的地方,而 length 就是陣列可以儲存的最大字節數。length 的型別是u2,u2是無符號的16位元整數,因此理論上允許的的最大長度是2^16-1=65535。所以上面byte陣列的最大長度可以是65535
2.執行時限制
String 執行時的限制主要體現在 String 的建構函式上。下面是 String 的一個建構函式:
publicString(charvalue[], int offset, int count) {
...
}
上面的count值就是字串的最大長度。在Java中,int的最大長度是2^31-1。所以在執行時,String 的最大長度是2^31-1。
但是這個也是理論上的長度,實際的長度還要看你JVM的記憶體。我們來看下,最大的字串會占用多大的記憶體。
(2^31-1)*16/8/1024/1024/1024 = 2GB
所以在最壞的情況下,一個最大的字串要占用4GB的記憶體。如果你的虛擬機器不能分配這麽多記憶體的話,會直接報錯的。
補充 JDK9以後對String的儲存進行了最佳化。底層不再使用char陣列儲存字串,而是使用byte陣列。對於LATIN1字元的字串可以節省一倍的記憶體空間。
熱門推薦