Longueur maximale de la chaîne en Java - méthode d'appel length ()

150

En Java , quelle est la taille maximale qu'un Stringobjet peut avoir, en référence à l' length()appel de méthode?

Je sais que length()retourner la taille d'un Stringcomme un char [];

taichi
la source
5
Alors que la longueur de a Stringest théoriquement Integer.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.
200_success

Réponses:

169

Compte tenu des Stringclasses lengthmé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 Strings), 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 ncomposants, nous disons nest la longueur du tableau; les composants du tableau sont référencés à l'aide d'indices entiers de 0à n - 1, inclus.

De plus, l'indexation doit se faire par intvaleurs, comme mentionné dans la section 10.4 :

Les tableaux doivent être indexés par des intvaleurs;

Par conséquent, il apparaît que la limite est effectivement 2^31 - 1, car il s'agit de la valeur maximale pour une intvaleur non négative .

Cependant, il y aura probablement d'autres limitations, telles que la taille maximale allouable pour un tableau.

coobird
la source
26
Integer.MAX_VALUE vaut 2 ^ 31-1, en fait. :)
Michael Myers
1
Bonne réponse homme! J'ai jeté un coup d'œil sur le code source de String.java et c'est vrai, 'count' est la variable int qui renvoie la longueur du tableau char, et le tableau char est stocké sur la variable 'value' (comme char []) Cela signifie que la taille de la chaîne pourrait être d'environ 2 Go. Bien sûr, il pourrait y avoir des limitations pour allouer une telle taille de mémoire. Merci!
taichi
5
J'ai juste essayé de définir un littéral de chaîne dans un programme java hello world qui était plus long que 65546. javacdonne 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
dlamblin
2
@dlamblin: Cela sonne comme une limitation de javacpour String littéraux (pas des Stringobjets), que je ne peux trouver aucune référence à des limites de taille à Stringlittéraux dans la spécification du langage Java et JVM spécification. J'ai essayé de créer un Stringlitté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.lengthplus grand que 100000.)
coobird
3
@Premraj C'était il y a trois ans alors j'ai dû y réfléchir. ;) Ce que je voulais dire, c'était; pour construire une chaîne de taille maximale, vous avez besoin de beaucoup de mémoire, peut-être plus que ce que vous avez de toute façon. Vous avez besoin de deux octets par caractère ~ 4 Go, mais vous devez le construire à partir d'un StringBuilder ou char [] ce qui signifie que vous avez besoin de deux octets supplémentaires par caractère pour le créer en premier lieu, c'est-à-dire un autre ~ 4 Go (au moins temporairement)
Peter Lawrey
25

java.io.DataInput.readUTF()et java.io.DataOutput.writeUTF(String)dire qu'un Stringobjet 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 DataInputet 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 intne signifie pas toujours que sa valeur maximale autorisée est Integer.MAX_VALUE. Au lieu de cela, dans la plupart des cas, intest 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 intsont convertis en intavant le calcul (si ma mémoire est bonne) et c'est une raison de choisir intquand 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 Stringobjet.

Stringles objets peuvent avoir beaucoup plus de caractères lors de l'exécution. Cependant, si vous souhaitez utiliser des Stringobjets avec des interfaces DataInputet DataOutput, il vaut mieux éviter d'utiliser des Stringobjets trop longs . J'ai trouvé cette limitation lorsque j'ai implémenté des équivalents Objective-C de DataInput.readUTF()et DataOutput.writeUTF(String).

Takahiko Kawasaki
la source
1
Cela devrait être la réponse par défaut.
Nick
20

É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.

Michael Myers
la source
9

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 StringBuildermaximum a été atteint alors 1207959550que mon char[]maximum a atteint (2 ^ 31) -3. Il semble que AbstractStringBuilderdouble la taille de son interne char[]pour le faire croître, ce qui cause probablement le problème.

Dantiston
la source
1
Un traitement pratique très utile de la question
Pavlo Maistrenko
5

apparemment, il est lié à un int, qui est 0x7FFFFFFF (2147483647).

Francis
la source
4

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.

Shanmugavel
la source
0

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 encodeUTF8mé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 charcount
Vous pouvez trouver la plage de points de code Unicode modifiée de JVM, à partir du lien struct utf8 ci-dessus.

DHS
la source