Answers:
考虑到String
该类的length
方法返回an int
,则该方法将返回的最大长度为Integer.MAX_VALUE
,即2^31 - 1
(或大约20亿)。
在数组的长度和索引方面(例如char[]
,这可能是内部数据表示的实现方式String
),Java SE 7版的《 Java语言规范》的第10章:数组表示以下内容:
数组中包含的变量没有名称。而是由使用非负整数索引值的数组访问表达式引用它们。这些变量称为数组的 组件。如果一个数组有
n
分量,那么我们说的n
是数组的 长度。数组的组成部分使用从0
到的整数索引n - 1
(含)进行引用。
此外,int
如第10.4节所述,索引必须按值进行:
数组必须按
int
值建立索引;
因此,似乎限制确实是2^31 - 1
,因为这是非负值的int
最大值。
但是,可能还会有其他限制,例如数组的最大可分配大小。
javac
给出了该文字过长的错误:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
javac
对String
文字(不是String
对象)的限制,因为我String
在Java语言规范和JVM规范中找不到对文字大小限制的任何引用。我尝试制作一个String
大于100,000个字符的文字,并且Eclipse编译器在编译它时没有问题。(运行该程序能够显示该文字的String.length
大小大于100,000。)
java.io.DataInput.readUTF()
并java.io.DataOutput.writeUTF(String)
说一个String
对象由两个字节的长度信息和字符串中每个字符的修改后的UTF-8表示形式表示。由此得出结论,当与DataInput
和一起使用时,字符串的长度受字符串的修改后的UTF-8表示形式的字节数限制DataOutput
。
另外,在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
是没有特殊原因时选择的原因之一。
编译时的最大长度最多为65536。再次注意,该长度是修改后的UTF-8表示形式的字节数,而不是String
对象中的字符数。
String
对象可能在运行时具有更多字符。但是,如果要String
与DataInput
和DataOutput
接口一起使用对象,最好避免使用太长的String
对象。我发现这个限制时我实现的目标C当量DataInput.readUTF()
和DataOutput.writeUTF(String)
。
我有一台具有8GB RAM的2010 iMac,运行带有Java 1.8.0_25的Eclipse Neon.2版本(4.6.2)。使用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
StringBuilder
附言:我不确定为什么我在(2 ^ 31)-3 1207959550
时char[]
达到最大值。似乎将AbstractStringBuilder
其内部的大小加倍以char[]
使其生长,所以可能导致了问题。
String类的length()方法的Return类型是int。
public int length()
请参阅http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length()
所以int的最大值是2147483647。
字符串在内部被视为char数组,因此在最大范围内完成了索引。这意味着我们无法索引第2147483648号成员,因此java中String的最大长度为2147483647。
在Java中,原始数据类型int是4个字节(32位)。由于将1位(MSB)用作符号位,因此范围限制在-2 ^ 31至2 ^ 31-1(-2147483648至2147483647)之内。我们不能使用负值进行索引,因此显然可以使用的范围是0到2147483647。
正如川崎隆彦的答案中提到的那样,java以修改后的UTF-8形式表示Unicode字符串,而在JVM-Spec CONSTANT_UTF8_info Structure中,长度分配了2个字节(而不是String的字符数)。
为了扩展答案,ASM jvm字节码库的putUTF8
method包含以下内容:
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
method:
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
指望
你可以找到JVM的改性Unicode代码点范围,从上面的UTF8结构的链接。
String
理论上讲aInteger.MAX_VALUE
的长度是多少,但是源中字符串文字的长度似乎仅限于65535字节的UTF-8数据。