Respuestas:
Teniendo en cuenta que el método de la String
clase length
devuelve un int
, la longitud máxima que devolvería el método sería Integer.MAX_VALUE
, que es 2^31 - 1
(o aproximadamente 2 mil millones).
En términos de longitudes e indexación de matrices, (como char[]
, probablemente, la forma en que se implementa la representación de datos internos para String
s), el Capítulo 10: Matrices de la especificación del lenguaje Java, Java SE 7 Edition dice lo siguiente:
Las variables contenidas en una matriz no tienen nombres; en su lugar, se hace referencia a ellas mediante expresiones de acceso a matriz que usan valores de índice de enteros no negativos. Estas variables se denominan componentes de la matriz. Si una matriz tiene
n
componentes, decimos quen
es la longitud de la matriz; Se hace referencia a los componentes de la matriz utilizando índices enteros desde0
hastan - 1
, inclusive.
Además, la indexación debe ser por int
valores, como se menciona en la Sección 10.4 :
Las matrices deben indexarse por
int
valores;
Por lo tanto, parece que el límite es 2^31 - 1
, ya que ese es el valor máximo para un int
valor no negativo .
Sin embargo, probablemente habrá otras limitaciones, como el tamaño máximo asignable para una matriz.
javac
da un error acerca de que ese literal es demasiado largo:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
javac
de String
los literales (no String
objetos), como no puedo encontrar ninguna referencia a los límites de tamaño de String
literales en la especificación del lenguaje Java y JVM especificación. Intenté hacer un String
literal que tuviera más de 100,000 caracteres, y el compilador de Eclipse no tuvo problemas para compilarlo. (Y ejecutar el programa fue capaz de mostrar que el literal tenía String.length
más de 100,000)
java.io.DataInput.readUTF()
y java.io.DataOutput.writeUTF(String)
digamos que un String
objeto está representado por dos bytes de información de longitud y la representación UTF-8 modificada de cada carácter en la cadena. Esto concluye que la longitud de la cadena está limitada por el número de bytes de la representación UTF-8 modificada de la cadena cuando se usa con DataInput
y DataOutput
.
Además, la especificaciónCONSTANT_Utf8_info
encontrada en la especificación de máquina virtual Java define la estructura de la siguiente manera.
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
Puede encontrar que el tamaño de 'longitud' es de dos bytes .
Que el tipo de retorno de un determinado método (p String.length()
. Ej. ) int
No siempre significa que su valor máximo permitido es Integer.MAX_VALUE
. En cambio, en la mayoría de los casos, int
se elige solo por razones de rendimiento. La especificación del lenguaje Java dice que los enteros cuyo tamaño es más pequeño que el de int
se convierten int
antes del cálculo (si mi memoria me sirve correctamente) y es una razón para elegir int
cuando no hay una razón especial.
La longitud máxima en el momento de la compilación es como máximo 65536. Observe nuevamente que la longitud es el número de bytes de la representación UTF-8 modificada , no el número de caracteres en un String
objeto.
String
los objetos pueden tener muchos más personajes en tiempo de ejecución. Sin embargo, si desea utilizar String
objetos DataInput
e DataOutput
interfaces, es mejor evitar el uso de String
objetos demasiado largos . Encontré esta limitación cuando implementé Objective-C equivalentes de DataInput.readUTF()
y DataOutput.writeUTF(String)
.
Como las matrices deben indexarse con enteros, la longitud máxima de una matriz es Integer.MAX_INT
(2 31 -1, o 2 147 483 647). Esto supone que tiene suficiente memoria para contener una matriz de ese tamaño, por supuesto.
Tengo un iMac 2010 con 8GB de RAM, ejecutando Eclipse Neon.2 Release (4.6.2) con Java 1.8.0_25. Con el argumento VM -Xmx6g, ejecuté el siguiente código:
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());
Esto imprime:
Requested array size exceeds VM limit
1207959550
Entonces, parece que el tamaño máximo de la matriz es ~ 1,207,959,549. Entonces me di cuenta de que en realidad no nos importa si Java se queda sin memoria: solo estamos buscando el tamaño máximo de matriz (que parece ser una constante definida en alguna parte). Entonces:
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);
}
}
Que imprime:
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
Entonces, parece que el máximo es Integer.MAX_VALUE - 2, o (2 ^ 31) - 3
PD No estoy seguro de por qué mi StringBuilder
máximo en 1207959550
mientras que mi char[]
máximo en (2 ^ 31) -3. Parece que AbstractStringBuilder
duplica el tamaño de su interno char[]
para hacerlo crecer, por lo que probablemente cause el problema.
El tipo de retorno del método length () de la clase String es int .
public int length ()
Consulte http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length ()
Entonces el valor máximo de int es 2147483647 .
La cadena se considera como matriz de caracteres internamente, por lo que la indexación se realiza dentro del rango máximo. Esto significa que no podemos indexar el miembro 2147483648, por lo que la longitud máxima de String en Java es 2147483647.
El tipo de datos primitivo int es de 4 bytes (32 bits) en java. Como 1 bit (MSB) se usa como bit de signo , el rango está restringido dentro de -2 ^ 31 a 2 ^ 31-1 (-2147483648 a 2147483647). No podemos usar valores negativos para la indexación, por lo que obviamente el rango que podemos usar es de 0 a 2147483647.
Como se menciona en la respuesta de Takahiko Kawasaki , java representa cadenas Unicode en forma de UTF-8 modificado y en la estructura JSTM-Spec CONSTANT_UTF8_info , se asignan 2 bytes a la longitud (y no el número de caracteres de la cadena).
Para extender la respuesta, el método de la biblioteca de bytecode jvm de ASM contiene esto: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);
}
}
...
}
Pero cuando la asignación de puntos de código> 1byte, llama al encodeUTF8
método:
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;
}
}
...
}
En este sentido, la longitud máxima de la cadena es 65535 bytes, es decir, la longitud de codificación utf-8. y no char
contar
Puede encontrar el rango de puntos de código Unicode modificado de JVM, desde el enlace utf8 struct anterior.
String
es teóricamenteInteger.MAX_VALUE
, la longitud de un literal de cadena en la fuente parece estar limitada a solo 65535 bytes de datos UTF-8.