La lunghezza massima della stringa in Java - chiamando il metodo length ()


150

In Java , qual è la dimensione massima che un Stringoggetto può avere, facendo riferimento alla length()chiamata del metodo?

So che length()restituisce la dimensione di a Stringcome a char [];


5
Mentre la lunghezza di a Stringè teoricamente Integer.MAX_VALUE, la lunghezza di una stringa letterale nella sorgente sembra essere limitata a soli 65535 byte di dati UTF-8.
200_successo

Risposte:


169

Considerando che il metodo della Stringclasse lengthrestituisce un int, la lunghezza massima che verrebbe restituita dal metodo sarebbe Integer.MAX_VALUE, che è 2^31 - 1(o circa 2 miliardi).

In termini di lunghezze e indicizzazione di array (come char[], ad esempio , che è probabilmente il modo in cui la rappresentazione interna dei dati è implementata per String), Capitolo 10: Array di The Java Language Specification, Java SE 7 Edition dice quanto segue:

Le variabili contenute in un array non hanno nomi; invece fanno riferimento a espressioni di accesso di array che utilizzano valori di indice di numeri interi non negativi. Queste variabili sono chiamate componenti dell'array. Se un array ha ncomponenti, diciamo che nè la lunghezza dell'array; i componenti dell'array sono referenziati usando indici interi da 0a n - 1, compreso.

Inoltre, l'indicizzazione deve essere basata su intvalori, come indicato nella Sezione 10.4 :

Le matrici devono essere indicizzate in base ai intvalori;

Pertanto, sembra che il limite sia effettivamente 2^31 - 1, poiché quello è il valore massimo per un intvalore non negativo .

Tuttavia, ci saranno probabilmente altre limitazioni, come la dimensione massima allocabile per un array.


26
Integer.MAX_VALUE è 2 ^ 31-1, in realtà. :)
Michael Myers

1
Grande risposta amico! Ho dato un'occhiata al codice sorgente String.java ed è giusto, "count" è la variabile int che restituisce la lunghezza dell'array char e l'array char viene archiviato nella variabile "value" (come char []) che la dimensione della stringa potrebbe essere di circa 2 GB. Naturalmente potrebbero esserci delle limitazioni per allocare tale dimensione di memoria. Grazie!
Taichi,

5
Ho appena provato a definire una stringa letterale in un programma java world hello che era più lungo di 65546. javacDà un errore riguardo a quel letterale che è troppo lungo:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
dlamblin,

2
@dlamblin: sembra un limite javacper i String letterali (non gli Stringoggetti), poiché non riesco a trovare alcun riferimento ai limiti di dimensione dei Stringletterali nelle Specifiche del linguaggio Java e Specifiche JVM. Ho provato a creare un valore Stringletterale di oltre 100.000 caratteri e il compilatore Eclipse non ha avuto problemi a compilarlo. (E l'esecuzione del programma è stata in grado di dimostrare che il valore letterale era String.lengthsuperiore a 100.000.)
coobird

3
@Premraj Era tre anni fa, quindi ho dovuto pensarci. ;) Quello che intendevo era; per creare una stringa di dimensioni massime è necessaria molta memoria, probabilmente più di quanto si abbia comunque. Sono necessari due byte per carattere ~ 4 GB, ma è necessario crearlo da StringBuilder o char [], il che significa che sono necessari altri due byte per carattere per crearlo in primo luogo, ovvero un altro ~ 4 GB (almeno temporaneamente)
Peter Lawrey,

25

java.io.DataInput.readUTF()e java.io.DataOutput.writeUTF(String)dire che un Stringoggetto è rappresentato da due byte di informazioni sulla lunghezza e dalla rappresentazione UTF-8 modificata di ogni carattere nella stringa. Questo conclude che la lunghezza di String è limitata dal numero di byte della rappresentazione UTF-8 modificata della stringa quando usata con DataInpute DataOutput.

Inoltre, la specifica diCONSTANT_Utf8_info trovato nella specifica della macchina virtuale Java definisce la struttura come segue.

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

Puoi scoprire che la dimensione di 'lunghezza' è di due byte .

Che il tipo restituito di un determinato metodo (ad es. String.length()) intNon significhi sempre che il suo valore massimo consentito è Integer.MAX_VALUE. Invece, nella maggior parte dei casi, intviene scelto solo per motivi di prestazioni. La specifica del linguaggio Java dice che gli interi le cui dimensioni sono inferiori a quelle di intvengono convertiti intprima del calcolo (se la mia memoria mi serve correttamente) ed è un motivo per scegliere intquando non c'è un motivo speciale.

La lunghezza massima al momento della compilazione è al massimo 65536. Notare ancora che la lunghezza è il numero di byte della rappresentazione UTF-8 modificata , non il numero di caratteri in un Stringoggetto.

Stringgli oggetti potrebbero essere in grado di avere molti più caratteri in fase di esecuzione. Tuttavia, se si desidera utilizzare Stringoggetti con DataInpute DataOutputinterfacce, è meglio evitare l'uso di Stringoggetti troppo lunghi . Ho trovato questa limitazione quando ho implementato equivalenti Objective-C di DataInput.readUTF()e DataOutput.writeUTF(String).


1
Questa dovrebbe essere la risposta predefinita.
Nick,

20

Poiché le matrici devono essere indicizzate con numeri interi, la lunghezza massima di una matrice è Integer.MAX_INT(2 31 -1 o 2 147 483 647). Ciò presuppone che tu abbia memoria sufficiente per contenere un array di quelle dimensioni, ovviamente.


9

Ho un iMac del 2010 con 8 GB di RAM, con Eclipse Neon.2 Release (4.6.2) con Java 1.8.0_25. Con l'argomento VM -Xmx6g, ho eseguito il seguente codice:

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());

Questo stampa:

Requested array size exceeds VM limit
1207959550

Quindi, sembra che la dimensione massima dell'array sia ~ 1.207.959.549. Poi ho capito che in realtà non ci importa se Java esaurisce la memoria: stiamo solo cercando la dimensione massima dell'array (che sembra essere una costante definita da qualche parte). Così:

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);
    }
}

Che stampa:

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

Quindi, sembra che il massimo sia Integer.MAX_VALUE - 2 o (2 ^ 31) - 3

PS Non sono sicuro del motivo per cui ho StringBuilderraggiunto 1207959550il char[]massimo mentre ( max. 2 ^ 31) -3. Sembra che AbstractStringBuilderraddoppi la dimensione del suo interno char[]per farla crescere, quindi probabilmente causa il problema.


1
Un trattamento pratico molto utile della domanda
Pavlo Maistrenko

5

apparentemente è associato a un int, che è 0x7FFFFFFF (2147483647).


4

Il tipo Return del metodo length () della classe String è int .

public int length ()

Consultare http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length ()

Quindi il valore massimo di int è 2147483647 .

La stringa viene considerata come matrice di caratteri internamente, quindi l'indicizzazione viene eseguita nell'intervallo massimo. Questo significa che non possiamo indicizzare il membro 2147483648. Quindi la lunghezza massima di String in Java è 2147483647.

Il tipo di dati primitivo int è 4 byte (32 bit) in java. Come 1 bit (MSB) viene utilizzato come bit di segno , l'intervallo è limitato da -2 ^ 31 a 2 ^ 31-1 (da -2147483648 a 2147483647). Non possiamo usare valori negativi per l'indicizzazione, quindi ovviamente l'intervallo che possiamo usare va da 0 a 2147483647.


0

Come menzionato nella risposta di Takahiko Kawasaki , java rappresenta le stringhe Unicode sotto forma di UTF-8 modificato e nella struttura CONSTANT_UTF8_info JVM-Spec , 2 byte sono assegnati alla lunghezza (e non al numero di caratteri della stringa).
Per estendere la risposta, il metodo della libreria bytecode ASM jvm contiene questo: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);
      }
    }
    ...
}

Ma quando la mappatura del punto di codice> 1 byte, chiama il encodeUTF8metodo:

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;
      }
    }
   ...
}

In questo senso, la lunghezza massima della stringa è 65535 byte, ovvero la lunghezza della codifica utf-8. e non charcontare
È possibile trovare l'intervallo di punti di codice Unicode modificato di JVM, dal collegamento sopra la struttura utf8.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.