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

在學習和開發過程當中,咱們常常會討論 short ,int 和 long 這些基本數據類型的取值範圍,可是對於 String 類型咱們好像不多注意它的「取值範圍」。那麼對於 String 類型,它到底有沒有長度限制呢?java

其實 String 類型的對象,他們是有長度限制的, String 對象並不能「存儲」無限長度的字符串。關於 String 的長度限制要從編譯時限制運行時限制兩方面考慮。程序員

編譯期限制

有JVM虛擬機相關知識的同窗確定知道,下面定義的字符串常量「自由之路」會被放入方法區的常量池中。數組

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。函數

//65535個d,編譯報錯
String s = "dd..dd";

//65534個d,編譯經過
String s1 = "dd..d";

上面的列子中長度爲65535的字符串s仍是編譯失敗了,可是長度爲65534的字符串 s1 編譯是成功的。這個好像和咱們剛剛的結論不符合。學習

其實,這時Javac編譯器的額外限制。在Javac的源代碼中能夠找到如下代碼:優化

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的時候,就會致使編譯失敗。this

這裏須要重點強調下的是:String 的限制並非對字符串長度的限制,而是對字符串底層存儲的限制。這句話可能比較抽象,下面舉個列子就清楚了。編碼

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,也沒超過Javac的限制,因此能夠編譯經過。

對於s2,一箇中文佔用3個字節,21845個正好佔用65535個字節,並且字符串長度是21845,並無超過javac對長度的限制,因此能夠編譯經過。

對於s3,一個英文字母d加上21845箇中文」自「佔用65535個字節,超過了最常限制,編譯失敗。

運行時限制

String 運行時的限制主要體如今 String 的構造函數上。下面是 String 的一個構造函數:

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,佔用的內存數不能超過虛擬機可以提供的最大值。

公衆號推薦

歡迎你們關注個人微信公衆號「程序員自由之路」

相關文章
相關標籤/搜索