溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

String最大長度是多少

發(fā)布時間:2021-09-17 11:09:29 來源:億速云 閱讀:130 作者:柒染 欄目:web開發(fā)

這篇文章將為大家詳細(xì)講解有關(guān)String最大長度是多少,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

前言

當(dāng)你看到這個問題“String長度限制是多少”時是不是感覺很無聊?的確,這就是我第一眼看到時的感覺。

但當(dāng)深入追蹤該問題時,才發(fā)現(xiàn)String的長度限制本身的意義并不重要,重要的是在此過程中會將大量知識點(diǎn)串聯(lián)起來,簡直是一個完美的問題。難怪在高階段的面試中會出現(xiàn)類似的問題。

帶大家追尋String長度的限制,需要提醒讀者的是,結(jié)論并不重要,重要的是分析的過程,以及涉及到的知識儲備。比如,String的底層實(shí)現(xiàn)、int類型的范圍、《Java虛擬機(jī)規(guī)范》、Java編譯器源碼實(shí)現(xiàn)等大量知識點(diǎn)。

String源碼追蹤

要看String類的長度限制,肯定要先從String的源碼實(shí)現(xiàn)看起,這里就以目前使用最多的JDK8為例來進(jìn)行說明。JDK9及以后String的底層實(shí)現(xiàn)有所變化,大家可參考《JDK9對String字符串的新一輪優(yōu)化》一文。

我們都知道,String類提供了一個length方法,我們是否可以直接通過這個方法得知String的最大長度?

/**  * Returns the length of this string.  * The length is equal to the number of <a href="Character.html#unicode">Unicode  * code units</a> in the string.  *  * @return  the length of the sequence of characters represented by this  *          object.  */ public int length() {     return value.length; }

這里文檔并沒有說明最大長度是多少,但我們可以從返回的結(jié)果類型得知一些線索。結(jié)果類型為int,也就是說int的取值范圍便是限制之一。

如果你知道int在正整數(shù)部分的取值范圍為2^31 -1那很好,如果不知道,可以查看對應(yīng)的包裝類Integer:

public final class Integer extends Number implements Comparable<Integer> {     /**      * A constant holding the minimum value an {@code int} can      * have, -2<sup>31</sup>.      */     @Native public static final int   MIN_VALUE = 0x80000000;      /**      * A constant holding the maximum value an {@code int} can      * have, 2<sup>31</sup>-1.      */     @Native public static final int   MAX_VALUE = 0x7fffffff;     // ... }

無論MIN_VALUE和MAX_VALUE的值或注釋都說明了int的取值范圍。此時計算一下String的最大長度應(yīng)該是:

2^31 - 1 = 2147483647

回到length方法,我們看到length的值是通過是value獲得的,而value在JDK8中是以char數(shù)組實(shí)現(xiàn)的:

public final class String     implements java.io.Serializable, Comparable<String>, CharSequence {     /** The value is used for character storage. */     private final char value[];     // ...    }

Java中內(nèi)碼(運(yùn)行內(nèi)存)中的char使用UTF16的方式編碼,一個char占用兩個字節(jié)。所以,還需要從將上面計算的值乘以2。

此時的計算公式為:

2^31-1 =2147483647 個16-bit Unicodecharacter  2147483647 * 2 = 4294967294 (Byte)   4294967294 / 1024 = 4194303.998046875 (KB)   4194303.998046875 / 1024 = 4095.9999980926513671875 (MB)   4095.9999980926513671875 / 1024 = 3.99999999813735485076904296875 (GB)

也就是說最大字符串占用內(nèi)存空間約等于4GB。但此時,如果你聲明一個長度為10萬的字符串,你會發(fā)現(xiàn)編譯器會拋出異常,提示信息如下:

錯誤: 常量字符串過長

不是說好的21億嗎?怎么10萬個就異常了呢?其實(shí)這個異常是由編譯期的限制決定的。

字符串常量池的編譯期限制

了解過JVM虛擬機(jī)的朋友肯定知道,當(dāng)通過字面量進(jìn)行字符串聲明時,在編譯之后會以常量的形式進(jìn)入到Class常量池。

String s = "程序新視界";

而常量池對String的長度是有限制的。常量池中的每一種數(shù)據(jù)項(xiàng)都有自己的類型。Java中的UTF-8編碼的Unicode字符串在常量池中以CONSTANT_Utf8類型表示。

在《Java虛擬機(jī)規(guī)范》中可以看到對String是通過CONSTANT_String_info來定義的。

String最大長度是多少

可以看到“string_index項(xiàng)的值必須是對常量池的有效索引,常量池在該索引處的項(xiàng)必須是CONSTANT_Utf8_info(&sect;4.4.7)結(jié)構(gòu)”。

繼續(xù)看對CONSTANT_Utf8_info的定義:

String最大長度是多少

length則指明了bytes[]數(shù)組的長度,類型為u2。同樣是在《Java虛擬機(jī)規(guī)范》中可以找到對u2的定義:

String最大長度是多少

u2表示兩個字節(jié)的無符號數(shù),1個字節(jié)有8位,2個字節(jié)就有16位。因此,u2可表示的最大值為2^16 - 1= 65535。

到這里,已經(jīng)得出了第二個限制,也就是Class文件中常量池的格式規(guī)定了,其字符串常量的長度不能超過65535。

此時,如果嘗試通過字面量聲明一個65535長度的字符串:

String s = "8888...8888";//其中有65535萬個字符"8"

編譯器還會拋出同樣的異常。這又是為什么呢?

這個問題我們同樣可以從《Java虛擬機(jī)規(guī)范》(4.7.3節(jié))中找到答案:

String最大長度是多少

原來是為了彌補(bǔ)早期設(shè)計時的一個bug,“長度剛好65535個字節(jié),且以1個字節(jié)長度的指令結(jié)束,這條指令不能被異常處理器處理”,因此就將數(shù)組的最大長度限制到了65534了。

如果你能夠查看JVM中編譯器部分的源碼,可以在Gen類中看到對此限制的代碼實(shí)現(xiàn):

/** Check a constant value and report if it is a string that is  *  too large.  */ private void checkStringConstant(DiagnosticPosition pos, Object constValue) {     if (nerrs != 0 || // only complain about a long string once         constValue == null ||         !(constValue instanceof String) ||         ((String)constValue).length() < Pool.MAX_STRING_LENGTH)         return;     log.error(pos, "limit.string");     nerrs++; }

其中Pool.MAX_STRING_LENGTH的定義如下:

public class Pool {     public static final int MAX_STRING_LENGTH = 0xFFFF;     //... }

再次嘗試聲明一個長度為65534的字符串,會發(fā)現(xiàn)可以正常編譯了。此時,可以得出結(jié)論,在編譯期字符串的最大長度為65534。

我們知道,Java是區(qū)分編譯期和運(yùn)行期的,那么在運(yùn)行期是否有長度限制呢?

運(yùn)行期的長度限制

String運(yùn)行期的限制主要體現(xiàn)在String的構(gòu)造函數(shù)上。String的一個構(gòu)造函數(shù)如下:

public String(char value[], int offset, int count) {    // ... }

其中參數(shù)count就是字符串的最大長度。此時的計算與前面的算法一致,這里先轉(zhuǎn)換為bit,然后再轉(zhuǎn)換為GB:

(2^31-1)*16/8/1024/1024/1024 = 4GB

也就是說,運(yùn)行時理論上可以支持4GB大小的字符串,超過這個限制就會拋出異常的。JDK9對String的存儲進(jìn)行了優(yōu)化,底層使用byte數(shù)組替代了char數(shù)組,對于純Latin1字符來說可以節(jié)省一半的空間。

當(dāng)然,這個4GB的限制是基于JVM能夠分配這么多可用的內(nèi)存的前提下的。

小結(jié)

通過上述的分析,可以得出結(jié)論:第一,在編譯期字符串的長度不能超過65534;第二,在運(yùn)行期,字符串的長度不能超過2^31-1,占用內(nèi)存(4GB)不能超過虛擬機(jī)所分配的最大內(nèi)存。

關(guān)于String最大長度是多少就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI