Réponses:
Compte tenu des String
classes length
méthode renvoie un int
, la longueur maximale qui serait renvoyée par la méthode serait Integer.MAX_VALUE
, qui est 2^31 - 1
(ou environ 2 milliards).
En termes de longueurs et d'indexation des tableaux, (comme char[]
, qui est probablement la façon dont la représentation des données internes est implémentée pour String
s), le chapitre 10: Tableaux de la spécification du langage Java, Java SE 7 Edition dit ce qui suit:
Les variables contenues dans un tableau n'ont pas de nom; à la place, ils sont référencés par des expressions d'accès au tableau qui utilisent des valeurs d'index d'entiers non négatifs. Ces variables sont appelées les composants du tableau. Si un tableau a des
n
composants, nous disonsn
est la longueur du tableau; les composants du tableau sont référencés à l'aide d'indices entiers de0
àn - 1
, inclus.
De plus, l'indexation doit se faire par int
valeurs, comme mentionné dans la section 10.4 :
Les tableaux doivent être indexés par des
int
valeurs;
Par conséquent, il apparaît que la limite est effectivement 2^31 - 1
, car il s'agit de la valeur maximale pour une int
valeur non négative .
Cependant, il y aura probablement d'autres limitations, telles que la taille maximale allouable pour un tableau.
javac
donne une erreur sur le fait que ce littéral est trop long:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
javac
pour String
littéraux (pas des String
objets), que je ne peux trouver aucune référence à des limites de taille à String
littéraux dans la spécification du langage Java et JVM spécification. J'ai essayé de créer un String
littéral de plus de 100 000 caractères et le compilateur Eclipse n'a pas eu de problème pour le compiler. (Et l'exécution du programme a pu montrer que le littéral avait un String.length
plus grand que 100000.)
java.io.DataInput.readUTF()
et java.io.DataOutput.writeUTF(String)
dire qu'un String
objet est représenté par deux octets d'informations de longueur et la représentation UTF-8 modifiée de chaque caractère de la chaîne. Cela conclut que la longueur de String est limitée par le nombre d'octets de la représentation UTF-8 modifiée de la chaîne lorsqu'elle est utilisée avec DataInput
et DataOutput
.
En outre, la spécification deCONSTANT_Utf8_info
trouvée dans la spécification de machine virtuelle Java définit la structure comme suit.
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
Vous pouvez constater que la taille de «longueur» est de deux octets .
Le fait que le type de retour d'une certaine méthode (par exemple String.length()
) soit int
ne signifie pas toujours que sa valeur maximale autorisée est Integer.MAX_VALUE
. Au lieu de cela, dans la plupart des cas, int
est choisi uniquement pour des raisons de performances. La spécification du langage Java dit que les entiers dont la taille est inférieure à celle de int
sont convertis en int
avant le calcul (si ma mémoire est bonne) et c'est une raison de choisir int
quand il n'y a pas de raison particulière.
La longueur maximale au moment de la compilation est au maximum de 65 536. Notez à nouveau que la longueur est le nombre d'octets de la représentation UTF-8 modifiée , et non le nombre de caractères dans un String
objet.
String
les objets peuvent avoir beaucoup plus de caractères lors de l'exécution. Cependant, si vous souhaitez utiliser des String
objets avec des interfaces DataInput
et DataOutput
, il vaut mieux éviter d'utiliser des String
objets trop longs . J'ai trouvé cette limitation lorsque j'ai implémenté des équivalents Objective-C de DataInput.readUTF()
et DataOutput.writeUTF(String)
.
Étant donné que les tableaux doivent être indexés avec des entiers, la longueur maximale d'un tableau est Integer.MAX_INT
(2 31 -1 ou 2 147 483 647). Cela suppose que vous ayez suffisamment de mémoire pour contenir un tableau de cette taille, bien sûr.
J'ai un iMac 2010 avec 8 Go de RAM, exécutant Eclipse Neon.2 Release (4.6.2) avec Java 1.8.0_25. Avec l'argument VM -Xmx6g, j'ai exécuté le code suivant:
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());
Cela imprime:
Requested array size exceeds VM limit
1207959550
Il semble donc que la taille maximale du tableau soit de ~ 1,207,959,549. Ensuite, j'ai réalisé que nous ne nous soucions pas vraiment de savoir si Java manquait de mémoire: nous cherchons simplement la taille maximale du tableau (qui semble être une constante définie quelque part). Alors:
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);
}
}
Quelles impressions:
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
Donc, il semble que le maximum soit Integer.MAX_VALUE - 2, ou (2 ^ 31) - 3
PS Je ne sais pas pourquoi mon StringBuilder
maximum a été atteint alors 1207959550
que mon char[]
maximum a atteint (2 ^ 31) -3. Il semble que AbstractStringBuilder
double la taille de son interne char[]
pour le faire croître, ce qui cause probablement le problème.
Le type de retour de la méthode length () de la classe String est int .
public int length ()
Reportez-vous à http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length ()
La valeur maximale de int est donc 2147483647 .
La chaîne est considérée comme un tableau de caractères en interne, donc l'indexation est effectuée dans la plage maximale. Cela signifie que nous ne pouvons pas indexer le 2147483648th membre. La longueur maximale de String en java est donc 2147483647.
Le type de données primitif int est de 4 octets (32 bits) en java. Comme 1 bit (MSB) est utilisé comme bit de signe , la plage est limitée entre -2 ^ 31 à 2 ^ 31-1 (-2147483648 à 2147483647). Nous ne pouvons pas utiliser de valeurs négatives pour l'indexation, donc évidemment la plage que nous pouvons utiliser va de 0 à 2147483647.
Comme mentionné dans la réponse de Takahiko Kawasaki , java représente les chaînes Unicode sous la forme d' UTF-8 modifié et dans la structure JVM-Spec CONSTANT_UTF8_info , 2 octets sont alloués à la longueur (et non au nombre de caractères de String).
Pour étendre la réponse, la méthode de la bibliothèque de bytecode jvm ASM contient ceci: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);
}
}
...
}
Mais lorsque le mappage de point de code> 1 octet, il appelle la encodeUTF8
méthode:
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 ce sens, la longueur maximale de la chaîne est de 65 535 octets, c'est-à-dire la longueur de codage utf-8. and not char
count
Vous pouvez trouver la plage de points de code Unicode modifiée de JVM, à partir du lien struct utf8 ci-dessus.
String
est théoriquementInteger.MAX_VALUE
, la longueur d'un littéral de chaîne dans la source semble être limitée à seulement 65 535 octets de données UTF-8.