Risposte:
Considerando che il metodo della String
classe length
restituisce 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
n
componenti, diciamo chen
è la lunghezza dell'array; i componenti dell'array sono referenziati usando indici interi da0
an - 1
, compreso.
Inoltre, l'indicizzazione deve essere basata su int
valori, come indicato nella Sezione 10.4 :
Le matrici devono essere indicizzate in base ai
int
valori;
Pertanto, sembra che il limite sia effettivamente 2^31 - 1
, poiché quello è il valore massimo per un int
valore non negativo .
Tuttavia, ci saranno probabilmente altre limitazioni, come la dimensione massima allocabile per un array.
javac
Dà un errore riguardo a quel letterale che è troppo lungo:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
javac
per i String
letterali (non gli String
oggetti), poiché non riesco a trovare alcun riferimento ai limiti di dimensione dei String
letterali nelle Specifiche del linguaggio Java e Specifiche JVM. Ho provato a creare un valore String
letterale 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.length
superiore a 100.000.)
java.io.DataInput.readUTF()
e java.io.DataOutput.writeUTF(String)
dire che un String
oggetto è 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 DataInput
e 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()
) int
Non significhi sempre che il suo valore massimo consentito è Integer.MAX_VALUE
. Invece, nella maggior parte dei casi, int
viene scelto solo per motivi di prestazioni. La specifica del linguaggio Java dice che gli interi le cui dimensioni sono inferiori a quelle di int
vengono convertiti int
prima del calcolo (se la mia memoria mi serve correttamente) ed è un motivo per scegliere int
quando 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 String
oggetto.
String
gli oggetti potrebbero essere in grado di avere molti più caratteri in fase di esecuzione. Tuttavia, se si desidera utilizzare String
oggetti con DataInput
e DataOutput
interfacce, è meglio evitare l'uso di String
oggetti troppo lunghi . Ho trovato questa limitazione quando ho implementato equivalenti Objective-C di DataInput.readUTF()
e DataOutput.writeUTF(String)
.
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.
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 StringBuilder
raggiunto 1207959550
il char[]
massimo mentre ( max. 2 ^ 31) -3. Sembra che AbstractStringBuilder
raddoppi la dimensione del suo interno char[]
per farla crescere, quindi probabilmente causa il problema.
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.
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 encodeUTF8
metodo:
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 char
contare
È possibile trovare l'intervallo di punti di codice Unicode modificato di JVM, dal collegamento sopra la struttura utf8.
String
è teoricamenteInteger.MAX_VALUE
, la lunghezza di una stringa letterale nella sorgente sembra essere limitata a soli 65535 byte di dati UTF-8.