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

IT小君   2021-09-15T00:22:08

Java 中String指的是length()方法调用,对象可能具有的最大大小是多少?

我知道将length()a 的大小返回String为 a char []

评论(7)
IT小君

考虑到String类的length方法返回int,该方法返回的最大长度为Integer.MAX_VALUE,即2^31 - 1(或大约 20 亿)。

在长度和数组的索引,(如而言char[],这可能是内部数据表示为实现方式StringS),第10章:数组Java语言规范,Java SE 7中版说以下内容:

数组中包含的变量没有名称;相反,它们由使用非负整数索引值的数组访问表达式引用。这些变量称为数组组件如果数组有n分量,我们说n数组长度数组的组成部分使用从0到 的整数索引引用n - 1,包括。

此外,索引必须按int值进行,如第 10.4 节所述

数组必须按int索引

因此,似乎极限确实是2^31 - 1,因为这是非负值的int最大值。

但是,可能会有其他限制,例如数组的最大可分配大小。

2021-09-15T00:22:09   回复
IT小君

java.io.DataInput.readUTF()java.io.DataOutput.writeUTF(String)说一个String对象被表示为两个字节的长度信息和UTF-8修改字符串中的每个字符的表示。这得出结论,当与DataInput和 一起使用时,字符串的长度受字符串的修改后的 UTF-8 表示的字节数限制DataOutput

此外,所述的说明书中CONSTANT_Utf8_info发现,在Java虚拟机规范定义如下的结构。

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

你可以发现'length'的大小是两个字节

某个方法的返回类型(例如String.length()int并不总是意味着其允许的最大值是Integer.MAX_VALUE相反,在大多数情况下,int选择只是出于性能原因。Java 语言规范说,大小小于 的整数在计算之前int被转换int(如果我没记错的话)并且int在没有特殊原因时选择它的原因之一。

编译时的最大长度最多为 65536。再次注意,长度是修改后的 UTF-8表示的字节数,而不是String对象中的字符数

String对象在运行时可能有更多的字符。但是,如果要使用String带有DataInputDataOutput接口的对象,最好避免使用太长的String对象。我发现这个限制时我实现的目标C当量DataInput.readUTF()DataOutput.writeUTF(String)

2021-09-15T00:22:09   回复
IT小君

由于数组必须以整数作为索引,因此数组的最大长度为Integer.MAX_INT(2 31 -1 或 2 147 483 647)。当然,这是假设您有足够的内存来容纳该大小的数组。

2021-09-15T00:22:09   回复
IT小君

我有一台带有 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我不知道为什么我StringBuilder在刷爆了1207959550,而我char[]在(2 ^ 31)刷爆-3。似乎将AbstractStringBuilder其内部的大小加倍char[]以增长它,因此这可能会导致问题。

2021-09-15T00:22:10   回复
IT小君

显然它绑定到一个整数,即 0x7FFFFFFF (2147483647)。

2021-09-15T00:22:10   回复
IT小君

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。

2021-09-15T00:22:10   回复
IT小君

正如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 代码点范围。

2021-09-15T00:22:10   回复