[英]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
是数组的长度; 使用从0
到n - 1
整数索引引用数组的组件。
此外,索引必须是int
值,如第 10.4 节所述:
数组必须由
int
值索引;
因此,似乎限制确实是2^31 - 1
,因为这是非负int
值的最大值。
但是,可能会有其他限制,例如数组的最大可分配大小。
java.io.DataInput.readUTF()
和java.io.DataOutput.writeUTF(String)
表示String
对象由两个字节的长度信息和字符串中每个字符的修改后的 UTF-8表示表示。 这得出结论,当与DataInput
和DataOutput
一起使用时,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 语言规范说,大小小于int
的int
在计算之前会转换为int
(如果我没记错的话),这也是在没有特殊原因时选择int
原因之一。
编译时的最大长度最多为 65536。再次注意,长度是修改后的 UTF-8表示的字节数,而不是String
对象中的字符数。
String
对象在运行时可能有更多的字符。 但是,如果要使用带有DataInput
和DataOutput
接口的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 我不知道为什么我的StringBuilder
在1207959550
达到最大值,而我的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.