Respostas:
Considerando que o método da String
classe length
retorna um int
, o comprimento máximo que seria retornado pelo método seria Integer.MAX_VALUE
, que é 2^31 - 1
(ou aproximadamente 2 bilhões).
Em termos de tamanho e indexação de matrizes (como char[]
provavelmente a maneira como a representação de dados interna é implementada para String
s), o Capítulo 10: Matrizes da especificação da linguagem Java, o Java SE 7 Edition diz o seguinte:
As variáveis contidas em uma matriz não têm nomes; em vez disso, eles são referenciados por expressões de acesso à matriz que usam valores de índice inteiro não negativo. Essas variáveis são chamadas de componentes da matriz. Se uma matriz tem
n
componentes, dizemos quen
é o comprimento da matriz; os componentes da matriz são referenciados usando índices inteiros de0
atén - 1
, inclusive.
Além disso, a indexação deve ser por int
valores, conforme mencionado na Seção 10.4 :
Matrizes devem ser indexadas por
int
valores;
Portanto, parece que o limite é realmente 2^31 - 1
, pois esse é o valor máximo para um int
valor não negativo .
No entanto, provavelmente haverá outras limitações, como o tamanho máximo alocável para uma matriz.
javac
dá um erro sobre esse ser literal muito longo:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
javac
para String
literais (não String
objetos), já que não consigo encontrar nenhuma referência aos limites de tamanho para String
literais na Java Language Specification e na JVM Specification. Tentei criar um String
literal com mais de 100.000 caracteres e o compilador Eclipse não teve problemas ao compilá-lo. (E, correndo o programa foi capaz de mostrar que o literal teve uma String.length
maior do que 100.000.)
java.io.DataInput.readUTF()
e java.io.DataOutput.writeUTF(String)
diga que um String
objeto é representado por dois bytes de informações de comprimento e pela representação UTF-8 modificada de cada caractere na sequência. Isso conclui que o comprimento da String é limitado pelo número de bytes da representação UTF-8 modificada da string quando usada com DataInput
e DataOutput
.
Além disso, a especificaçãoCONSTANT_Utf8_info
encontrada na especificação da máquina virtual Java define a estrutura da seguinte maneira.
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
Você pode achar que o tamanho do 'comprimento' é de dois bytes .
Que o tipo de retorno de um determinado método (por exemplo String.length()
) seja int
nem sempre significa que seu valor máximo permitido é Integer.MAX_VALUE
. Em vez disso, na maioria dos casos, int
é escolhido apenas por razões de desempenho. A especificação da linguagem Java diz que números inteiros cujo tamanho é menor que o de int
são convertidos para int
antes do cálculo (se minha memória me servir corretamente) e é uma das razões para escolher int
quando não há uma razão especial.
O comprimento máximo no tempo de compilação é no máximo 65536. Observe novamente que o comprimento é o número de bytes da representação UTF-8 modificada , não o número de caracteres em um String
objeto.
String
os objetos podem ter muito mais caracteres em tempo de execução. No entanto, se você deseja usar String
objetos com DataInput
e DataOutput
interfaces, é melhor evitar o uso de String
objetos muito longos . Encontrei essa limitação ao implementar os equivalentes Objective-C de DataInput.readUTF()
e DataOutput.writeUTF(String)
.
Como as matrizes devem ser indexadas com números inteiros, o comprimento máximo de uma matriz é Integer.MAX_INT
(2 31 -1 ou 2 147 483 647). Isso pressupõe que você tenha memória suficiente para armazenar uma matriz desse tamanho, é claro.
Eu tenho um iMac 2010 com 8 GB de RAM, executando o Eclipse Neon.2 Release (4.6.2) com Java 1.8.0_25. Com o argumento da VM -Xmx6g, executei o seguinte 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());
Isso imprime:
Requested array size exceeds VM limit
1207959550
Portanto, parece que o tamanho máximo da matriz é ~ 1.207.959.549. Então percebi que na verdade não nos importamos se o Java ficar sem memória: estamos apenas procurando o tamanho máximo da matriz (que parece ser uma constante definida em algum lugar). Assim:
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
Então, parece que o máximo é Inteiro.MAX_VALUE - 2 ou (2 ^ 31) - 3
PS: Não sei por que meu StringBuilder
limite máximo foi atingido 1207959550
enquanto meu char[]
limite máximo atingido (2 ^ 31) -3. Parece que AbstractStringBuilder
dobra o tamanho de seu interno char[]
para cultivá-lo, o que provavelmente causa o problema.
O tipo Return do método length () da classe String é int .
public int length ()
Consulte http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length ()
Portanto, o valor máximo de int é 2147483647 .
String é considerada como matriz de char internamente, portanto, a indexação é feita dentro do intervalo máximo. Isso significa que não podemos indexar o membro 2147483648. Portanto, o comprimento máximo de String em java é 2147483647.
O tipo de dados primitivo int é de 4 bytes (32 bits) em java. Como 1 bit (MSB) é usado como um bit de sinal , o intervalo é restrito dentro de -2 ^ 31 a 2 ^ 31-1 (-2147483648 a 2147483647). Não podemos usar valores negativos para indexação. Portanto, obviamente, o intervalo que podemos usar é de 0 a 2147483647.
Como mencionado na resposta de Takahiko Kawasaki , java representa seqüências de caracteres Unicode na forma de UTF-8 modificado e na estrutura CONSTANT_UTF8_info da JVM-Spec , 2 bytes são alocados no comprimento (e não no número de caracteres de String).
Para estender a resposta, o método da biblioteca ASM jvm bytecode contém: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);
}
}
...
}
Mas quando o mapeamento de ponto de código> 1byte, ele chama o 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;
}
}
...
}
Nesse sentido, o comprimento máximo da string é 65535 bytes, ou seja, o comprimento da codificação utf-8. e não char
conte
Você pode encontrar o intervalo de ponto de código Unicode modificado da JVM, no link struct utf8 acima.
String
é teoricamenteInteger.MAX_VALUE
, o comprimento de uma string literal na origem parece estar limitado a apenas 65535 bytes de dados UTF-8.