java中的String定義的字面量最大長度是多少
java的String物件底層是有字元陣列儲存的,理論上char[] 最大長度是int的最大值,實際
思路:
首先,String字面常量是由String類來維護的,並且在編譯時就可以確定(具體請參考String常量池)。因而,如果String字面常量存在一個最大的長度(目前暫且假設),而我們使用的字面常量又超過了這個極限,那麼,在編譯期間,編譯器就能夠給出錯誤資訊。因此,我們可以使用IO流生成Java檔案,檔案的內容就是宣告一個String物件,然後使用字面常量賦值,根據動態編譯結果,調整字面常量的長度,最後得出字面常量的最大長度值
根據以下程式碼得出結論(程式碼來自書《Java深入解析:透析Java本質的36個話題 》):
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; public class LiteralLength { public static void main(String[] args) throws Exception { String fileName = "D:/Literal.java"; StringBuilder prefix = new StringBuilder(); prefix.append("public class Literal{ String s = \""); int low = 0; int high = 100_0000; int mid = (low + high)/2; StringBuilder literal = new StringBuilder(high); int result; String ch = "A"; JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); //自定義錯誤輸出流 取代System的err OutputStream err = new OutputStream() { @Override public void write(int b) throws IOException { } }; int max = 0; for (int i = 0; i < mid; i++) { literal.append(ch); } while(low <= high){ StringBuilder fileContent = new StringBuilder(literal.length() + prefix.length() * 2); fileContent.append(prefix); fileContent.append(literal); fileContent.append("\";}"); FileWriter w = new FileWriter(fileName); BufferedWriter bw = new BufferedWriter(w); bw.write(fileContent.toString()); bw.close(); w.close();//生成java檔案 result = compiler.run(null,null,err,fileName); //程式碼點的數量 int codePointCount = literal.codePointCount(0,literal.length()); if(result == 0){//0表示沒有編譯錯誤 low = mid + 1; mid = (low + high)/2; max = codePointCount; for (int i = codePointCount; i < mid; i++) { literal.append(ch); } System.out.println("長度" + max + "編譯成功,增加長度至" + mid); }else{ //編譯錯誤,說明字面量太長 high = mid - 1; mid = (low + high)/2; System.err.println("長度" + codePointCount + "編譯失敗,減少長度至" + mid); int start = ch.length() == 1? mid : mid *2; literal.delete(start,literal.length()); } } err.close(); System.out.println("最大字面量長度:" + max); } }
輸出結果:
長度500000編譯失敗,減少長度至249999
長度249999編譯失敗,減少長度至124999
長度124999編譯失敗,減少長度至62499
長度62499編譯成功,增加長度至93749
長度93749編譯失敗,減少長度至78124
長度78124編譯失敗,減少長度至70311
長度70311編譯失敗,減少長度至66405
長度66405編譯失敗,減少長度至64452
長度64452編譯成功,增加長度至65428
長度65428編譯成功,增加長度至65916
長度65916編譯失敗,減少長度至65672
長度65672編譯失敗,減少長度至65550
長度65550編譯失敗,減少長度至65489長度65489編譯成功,增加長度至65519
長度65519編譯成功,增加長度至65534
長度65534編譯成功,增加長度至65542
長度65542編譯失敗,減少長度至65538
長度65538編譯失敗,減少長度至65536
長度65536編譯失敗,減少長度至65535
長度65535編譯失敗,減少長度至65534
最大字面量長度:65534
但是若 修改程式碼
String ch = "α";
結論 :最大字面量長度:32767
若 String ch = "字";
最大字面量長度:21845
在class檔案中,使用CONSTANT_Utf8_info表來存放各種常量字串,包括String字面常量,類或介面的全限定名,方法及變數的名稱、描述符等。CONSTANT_Utf8_info表的結構如表 所示。
從表3-1可知,CONSTANT_Utf8_info表使用2位元組來表示字串的長度,因此,bytes陣列的最大長度為216−1,即65535位元組。可是,為什麼4個字元(“A”、“á”、“字”與“㊣”)的執行結果各不相同呢?原因在於,在CONSTANT_Utf8_info表中,從“\u0001”~“\u007f”,bytes使用1位元組來表示,空字元(null,即“\u0000”)和從“\u0080”~“\u07ff”,使用2位元組來表示,從“\u0800”~“\uffff”,使用3位元組來表示,而對於增補字元,即程式碼點範圍在“U+10000”~“U+10FFFF”之間的字元,使用6位元組來表示。也可以這樣認為,增補字元是使用一個代理對來表示的,而代理對的取值範圍為“\ud800”~“\udfff”,這些字元都在“\u0800”~“\uffff”之間,每個代理字元使用3位元組表示,共6位元組。上述的儲存是在class檔案中的實現,不要與Java程式中的字元相混淆,對於Java程式來說,“A”、“á”、“字”都使用一個char型別變量表示,即2位元組,而“[插圖]”(增補字元)使用兩個char型別變量表示,即4位元組。
String字面常量的最大長度與String在記憶體中的最大長度是不一樣的,後者的最大長度為int型別的最大值,即2147483647,而前者根據字元(字元Unicode值)的不同,最大長度也不同,最大長度為65534(可手動修改class檔案,令輸出結果為65535)。
String字面常量的最大長度是由CONSTANT_Utf8_info表來決定的,該長度在編譯時確定,如果超過了CONSTANT_Utf8_info表bytes陣列所能表示的上限,就會產生編譯錯誤。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。