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

爪哇咖啡中,参考 length()方法调用,String对象的最大大小是多少?

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

295343 次浏览

由于数组必须用整数索引,因此数组的最大长度是 Integer.MAX_INT(231-1,或2147483647)。当然,这是假设您有足够的内存来容纳这样大小的数组。

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

在数组的长度和索引方面(例如 char[],这可能是 String实现内部数据表示的方式) ,Java 语言规范,JavaSE7版第10章: 数组说:

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

此外,索引必须是 int值,如 第10.4节所述:

数组必须按 int值进行索引;

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

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

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

java.io.DataInput.readUTF()java.io.DataOutput.writeUTF(String)表示,String对象由长度信息的 < em > 两个字节 表示,并由字符串中每个字符的 改良的 UTF-8表示。这就得出结论,当与 DataInputDataOutput一起使用时,String 的长度受到修改后的字符串 UTF-8表示形式的字节数的限制。

此外,Java 虚拟机规范中的 CONSTANT_Utf8_info规范定义了如下结构。

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

你会发现长度的大小是 两个字节

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

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

String对象在运行时可能具有更多的字符。但是,如果希望使用具有 DataInputDataOutput接口的 String对象,最好避免使用太长的 String对象。我在实现 Objective-C 等价物 DataInput.readUTF()DataOutput.writeUTF(String)时发现了这个限制。

String 类的 length ()方法的 Return 类型是 Int

Public int length ()

请参阅 http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length()

所以 int 的最大值是 < em > 2147483647

字符串在内部被认为是字符数组,因此索引是在最大范围内完成的。 这意味着我们不能索引第2147483648个成员,所以 Java 中 String 的最大长度是2147483647。

原始数据类型 int 在 java 中为4字节(32位)。由于1位(MSB)被用作 符号位,因此范围被限制在 -2 ^ 31比2 ^ 31-1(- 2147483648至2147483647)内。 我们不能使用负值来索引。所以很明显,我们可以使用的范围是从0到2147483647。

我有一台2010年的 iMac,内存为8GB,运行 Eclipse Neon.2发行版(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

另外,我不知道为什么我的 StringBuilder1207959550时达到了最大值,而我的 char[]在(2 ^ 31)-3时达到了最大值。看起来 AbstractStringBuilder的内部 char[]的大小增加了一倍,所以可能导致了这个问题。

正如在 川崎隆彦的回答中提到的,java 以 改良的 UTF-8的形式表示 Unicode 字符串,在 JVM-Spec CONSTANT _ UTF8 _ info 结构中,将2字节分配给长度(而不是 no。字符串的字符数)。
为了扩展这个答案,字节码库的 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);
}
}
...
}

但是当代码点映射 > 1字节时,它调用 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 struct 链接中找到修改后的 -Unicode 代码点范围。