自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

String最大長(zhǎng)度是多少?涉及知識(shí)面太多,不要錯(cuò)過(guò)!

開發(fā) 前端
當(dāng)你看到這個(gè)問(wèn)題“String長(zhǎng)度限制是多少”時(shí)是不是感覺很無(wú)聊?的確,這就是我第一眼看到時(shí)的感覺。

[[397376]]

本文轉(zhuǎn)載自微信公眾號(hào)「程序新視界」,作者二師兄。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序新視界公眾號(hào)。  

前言

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

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

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

String源碼追蹤

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

我們都知道,String類提供了一個(gè)length方法,我們是否可以直接通過(guò)這個(gè)方法得知String的最大長(zhǎng)度?

  1. /** 
  2.  * Returns the length of this string. 
  3.  * The length is equal to the number of <a href="Character.html#unicode">Unicode 
  4.  * code units</a> in the string. 
  5.  * 
  6.  * @return  the length of the sequence of characters represented by this 
  7.  *          object. 
  8.  */ 
  9. public int length() { 
  10.     return value.length; 

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

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

  1. public final class Integer extends Number implements Comparable<Integer> { 
  2.     /** 
  3.      * A constant holding the minimum value an {@code int} can 
  4.      * have, -2<sup>31</sup>. 
  5.      */ 
  6.     @Native public static final int   MIN_VALUE = 0x80000000; 
  7.  
  8.     /** 
  9.      * A constant holding the maximum value an {@code int} can 
  10.      * have, 2<sup>31</sup>-1. 
  11.      */ 
  12.     @Native public static final int   MAX_VALUE = 0x7fffffff; 
  13.     // ... 

無(wú)論MIN_VALUE和MAX_VALUE的值或注釋都說(shuō)明了int的取值范圍。此時(shí)計(jì)算一下String的最大長(zhǎng)度應(yīng)該是:

  1. 2^31 - 1 = 2147483647 

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

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

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

此時(shí)的計(jì)算公式為:

  1. 2^31-1 =2147483647 個(gè)16-bit Unicodecharacter 
  2.  
  3. 2147483647 * 2 = 4294967294 (Byte) 
  4.   
  5. 4294967294 / 1024 = 4194303.998046875 (KB) 
  6.   
  7. 4194303.998046875 / 1024 = 4095.9999980926513671875 (MB) 
  8.   
  9. 4095.9999980926513671875 / 1024 = 3.99999999813735485076904296875 (GB) 

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

錯(cuò)誤: 常量字符串過(guò)長(zhǎng)

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

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

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

  1. String s = "程序新視界"

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

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

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

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

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

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

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

此時(shí),如果嘗試通過(guò)字面量聲明一個(gè)65535長(zhǎng)度的字符串:

  1. String s = "8888...8888";//其中有65535萬(wàn)個(gè)字符"8" 

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

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

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

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

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

其中Pool.MAX_STRING_LENGTH的定義如下:

  1. public class Pool { 
  2.     public static final int MAX_STRING_LENGTH = 0xFFFF; 
  3.     //... 

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

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

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

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

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

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

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

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

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

小結(jié)

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

 

結(jié)論很簡(jiǎn)單,但本篇文章分析時(shí)所使用的知識(shí)和思路你學(xué)到了嗎?如果沒(méi)有,趕緊補(bǔ)一補(bǔ)吧。

 

責(zé)任編輯:武曉燕 來(lái)源: 程序新視界
相關(guān)推薦

2020-11-10 13:47:29

String源碼長(zhǎng)度限制

2022-02-17 10:56:33

Redis數(shù)據(jù)系統(tǒng)

2009-12-15 17:19:23

架構(gòu)師梁遠(yuǎn)華聚聚呀

2020-06-15 08:25:35

Linux 系統(tǒng) 數(shù)據(jù)

2021-11-07 07:51:01

JavaString字符串

2022-05-20 15:27:41

React工具Vue

2011-06-23 08:50:46

JavaAndroidOracle

2020-12-16 15:37:19

Python編程語(yǔ)言開發(fā)

2023-04-11 16:31:10

開發(fā)React 庫(kù)Web

2020-07-21 08:14:13

TypeScrip

2010-10-08 14:45:43

mysql中int

2013-05-31 15:57:59

Windows 8.1

2021-10-08 08:00:00

Java開發(fā)功能

2020-07-09 07:37:06

數(shù)據(jù)庫(kù)Redis工具

2020-08-17 17:22:34

VSCode插件開發(fā)編碼

2023-08-11 08:19:39

JavaStream API

2020-11-17 16:22:45

開源工具報(bào)表

2021-03-08 21:57:29

手機(jī)科技數(shù)碼

2023-10-20 21:16:33

物聯(lián)網(wǎng)通訊線
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)