簡體   English   中英

Java 中字符串的最大長度 - 調用 length() 方法

[英]String's Maximum length in Java - calling length() method

Java 中,參考length()方法調用, String對象可能具有的最大大小是多少?

我知道length()String的大小作為char []

考慮到String類的length方法返回一個int ,該方法返回的最大長度將為Integer.MAX_VALUE ,即2^31 - 1 (或大約 20 億)。

在數組的長度和索引方面,(例如char[] ,這可能是為String s 實現內部數據表示的方式),第 10 章: Java 語言規范的數組,Java SE 7 版說如下:

數組中包含的變量沒有名稱; 相反,它們由使用非負整數索引值的數組訪問表達式引用。 這些變量稱為數組的組件 如果一個數組有n分量,我們說n是數組的長度 使用從0n - 1整數索引引用數組的組件。

此外,索引必須是int值,如第 10.4 節所述

數組必須由int值索引;

因此,似乎限制確實是2^31 - 1 ,因為這是非負int值的最大值。

但是,可能會有其他限制,例如數組的最大可分配大小。

java.io.DataInput.readUTF()java.io.DataOutput.writeUTF(String)表示String對象由兩個字節的長度信息和字符串中每個字符的修改后的 UTF-8表示表示。 這得出結論,當與DataInputDataOutput一起使用時,String 的長度受字符串的修改后的 UTF-8 表示的字節數限制。

另外,Java虛擬機規范中CONSTANT_Utf8_info規范定義了如下結構。

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

你可以發現'length'的大小是兩個字節

某個方法(例如String.length() )的返回類型是int並不總是意味着其允許的最大值是Integer.MAX_VALUE 相反,在大多數情況下,選擇int只是出於性能原因。 Java 語言規范說,大小小於intint在計算之前會轉換為int (如果我沒記錯的話),這也是在沒有特殊原因時選擇int原因之一。

編譯時的最大長度最多為 65536。再次注意,長度是修改后的 UTF-8表示的字節數,而不是String對象中的字符數。

String對象在運行時可能有更多的字符。 但是,如果要使用帶有DataInputDataOutput接口的String對象,最好避免使用太長的String對象。 當我實現DataInput.readUTF()DataOutput.writeUTF(String) Objective-C 等價物時,我發現了這個限制。

由於數組必須以整數作為索引,因此數組的最大長度為Integer.MAX_INT (2 31 -1 或 2 147 483 647)。 當然,這是假設您有足夠的內存來容納該大小的數組。

我有一台帶有 8GB RAM 的 2010 iMac,運行 Eclipse Neon.2 Release (4.6.2) 和 Java 1.8.0_25。 使用 VM 參數 -Xmx6g,我運行了以下代碼:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < Integer.MAX_VALUE; i++) {
    try {
        sb.append('a');
    } catch (Throwable e) {
        System.out.println(i);
        break;
    }
}
System.out.println(sb.toString().length());

這打印:

Requested array size exceeds VM limit
1207959550

因此,最大數組大小似乎是 ~1,207,959,549。 然后我意識到我們實際上並不關心 Java 是否耗盡內存:我們只是在尋找最大數組大小(這似乎是在某處定義的常量)。 所以:

for (int i = 0; i < 1_000; i++) {
    try {
        char[] array = new char[Integer.MAX_VALUE - i];
        Arrays.fill(array, 'a');
        String string = new String(array);
        System.out.println(string.length());
    } catch (Throwable e) {
        System.out.println(e.getMessage());
        System.out.println("Last: " + (Integer.MAX_VALUE - i));
        System.out.println("Last: " + i);
    }
}

哪個打印:

Requested array size exceeds VM limit
Last: 2147483647
Last: 0
Requested array size exceeds VM limit
Last: 2147483646
Last: 1
Java heap space
Last: 2147483645
Last: 2

因此,最大值似乎是 Integer.MAX_VALUE - 2 或 (2^31) - 3

PS 我不知道為什么我的StringBuilder1207959550達到最大值,而我的char[]在 (2^31)-3 達到最大值。 似乎AbstractStringBuilder將其內部char[]的大小加倍以增大它,因此這可能會導致問題。

String 類的 length() 方法的返回類型是int

公共整數長度()

參考http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length()

所以 int 的最大值是2147483647

String在內部被認為是char數組,所以索引是在最大范圍內完成的。 這意味着我們不能索引第 2147483648 個成員。所以 java 中 String 的最大長度是 2147483647。

java中的原始數據類型int是4個字節(32位)。由於1位(MSB)用作符號位,范圍被限制在-2^31到2^31-1 (-2147483648到2147483647)內。 我們不能為索引使用負值。所以顯然我們可以使用的范圍是從 0 到 2147483647。

顯然它綁定到一個整數,即 0x7FFFFFFF (2147483647)。

正如Takahiko Kawasaki 的回答中提到,java 以修改后的 UTF-8的形式表示 Unicode 字符串,在 JVM-Spec CONSTANT_UTF8_info Structure 中,2 個字節被分配給長度(而不是字符串的字符數)。
為了擴展答案, ASM jvm 字節碼庫的putUTF8方法包含以下內容:

public ByteVector putUTF8(final String stringValue) {
    int charLength = stringValue.length();
    if (charLength > 65535) {   
   // If no. of characters> 65535, than however UTF-8 encoded length, wont fit in 2 bytes.
      throw new IllegalArgumentException("UTF8 string too large");
    }
    for (int i = 0; i < charLength; ++i) {
      char charValue = stringValue.charAt(i);
      if (charValue >= '\u0001' && charValue <= '\u007F') {
        // Unicode code-point encoding in utf-8 fits in 1 byte.
        currentData[currentLength++] = (byte) charValue;
      } else {
        // doesnt fit in 1 byte.
        length = currentLength;
        return encodeUtf8(stringValue, i, 65535);
      }
    }
    ...
}

但是當代碼點映射 > 1byte 時,它​​會調用encodeUTF8方法:

final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength /*= 65535 */) {
    int charLength = stringValue.length();
    int byteLength = offset;
    for (int i = offset; i < charLength; ++i) {
      char charValue = stringValue.charAt(i);
      if (charValue >= 0x0001 && charValue <= 0x007F) {
        byteLength++;
      } else if (charValue <= 0x07FF) {
        byteLength += 2;
      } else {
        byteLength += 3;
      }
    }
   ...
}

從這個意義上說,最大字符串長度為 65535 字節,即 utf-8 編碼長度。 而不是char
您可以從上面的 utf8 結構鏈接中找到 JVM 的修改后的 Unicode 代碼點范圍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM