Antworten:
Unter Berücksichtigung der String
Klasse length
Methode gibt ein int
, die maximale Länge , die durch das Verfahren zurückgeführt werden würde , wäre Integer.MAX_VALUE
, das ist 2^31 - 1
(oder ungefähr 2 Milliarden.)
In Bezug auf Länge und Indizierung von Arrays (z. B. char[]
wie die interne Datendarstellung wahrscheinlich für String
s implementiert wird ) wird in Kapitel 10: Arrays der Java-Sprachspezifikation, Java SE 7 Edition , Folgendes angegeben:
Die in einem Array enthaltenen Variablen haben keine Namen. Stattdessen werden sie durch Array-Zugriffsausdrücke referenziert, die nichtnegative ganzzahlige Indexwerte verwenden. Diese Variablen werden als Komponenten des Arrays bezeichnet. Wenn ein Array
n
Komponenten enthält,n
ist dies die Länge des Arrays. Auf die Komponenten des Arrays wird mit ganzzahligen Indizes von0
bisn - 1
einschließlich verwiesen .
Darüber hinaus muss die Indizierung nach int
Werten erfolgen, wie in Abschnitt 10.4 erwähnt :
Arrays müssen durch
int
Werte indiziert werden.
Daher scheint es, dass die Grenze tatsächlich ist 2^31 - 1
, da dies der Maximalwert für einen nichtnegativen int
Wert ist.
Es wird jedoch wahrscheinlich andere Einschränkungen geben, z. B. die maximal zuweisbare Größe für ein Array.
javac
gibt einen Fehler, dass dieses Literal zu lang ist:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
javac
für String
Literale (keine String
Objekte), da ich String
in der Java-Sprachspezifikation und der JVM-Spezifikation keinen Verweis auf Größenbeschränkungen für Literale finden kann . Ich habe versucht, ein String
Literal zu erstellen, das größer als 100.000 Zeichen war, und der Eclipse-Compiler hatte kein Problem beim Kompilieren. (Und das Ausführen des Programms konnte zeigen, dass das Literal String.length
mehr als 100.000 hatte.)
java.io.DataInput.readUTF()
und java.io.DataOutput.writeUTF(String)
sagen, dass ein String
Objekt durch zwei Bytes Längeninformation und die modifizierte UTF-8- Darstellung jedes Zeichens in der Zeichenfolge dargestellt wird. Dies schließt daraus, dass die Länge des Strings durch die Anzahl der Bytes der modifizierten UTF-8-Darstellung des Strings begrenzt ist, wenn er mit DataInput
und verwendet wird DataOutput
.
Darüber hinaus Die SpezifikationCONSTANT_Utf8_info
definiert Gefunden in der Java Virtual Machine Spezifikation die Struktur wie folgt.
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
Sie können feststellen, dass die Größe von 'Länge' zwei Bytes beträgt .
Dass der Rückgabetyp einer bestimmten Methode (z. B. String.length()
) ist, int
bedeutet nicht immer, dass der zulässige Maximalwert ist Integer.MAX_VALUE
. Stattdessen wird in den meisten Fällen int
nur aus Leistungsgründen gewählt. Die Java-Sprachspezifikation besagt, dass Ganzzahlen, deren Größe kleiner als die von int
ist, int
vor der Berechnung konvertiert werden (wenn mein Speicher mir richtig dient), und es ist ein Grund zu wählen, int
wenn es keinen besonderen Grund gibt.
Die maximale Länge zur Kompilierungszeit beträgt höchstens 65536. Beachten Sie erneut, dass die Länge die Anzahl der Bytes der geänderten UTF-8- Darstellung und nicht die Anzahl der Zeichen in einem String
Objekt ist.
String
Objekte können zur Laufzeit möglicherweise viel mehr Zeichen enthalten. Wenn Sie jedoch String
Objekte mit DataInput
und DataOutput
Schnittstellen verwenden möchten , ist es besser, zu lange String
Objekte zu vermeiden . Ich habe diese Einschränkung festgestellt, als ich Objective-C-Äquivalente von DataInput.readUTF()
und implementiert habe DataOutput.writeUTF(String)
.
Da Arrays mit ganzen Zahlen indiziert werden müssen, beträgt die maximale Länge eines Arrays Integer.MAX_INT
(2 31 -1 oder 2 147 483 647). Dies setzt natürlich voraus, dass Sie über genügend Speicher verfügen, um ein Array dieser Größe aufzunehmen.
Ich habe einen 2010 iMac mit 8 GB RAM, auf dem Eclipse Neon.2 Release (4.6.2) mit Java 1.8.0_25 ausgeführt wird. Mit dem VM-Argument -Xmx6g habe ich den folgenden Code ausgeführt:
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());
Dies druckt:
Requested array size exceeds VM limit
1207959550
Es scheint also, dass die maximale Arraygröße ~ 1.207.959.549 beträgt. Dann wurde mir klar, dass es uns eigentlich egal ist, ob Java nicht genügend Arbeitsspeicher hat: Wir suchen nur nach der maximalen Arraygröße (die eine irgendwo definierte Konstante zu sein scheint). So:
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);
}
}
Welche Drucke:
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
Es scheint also, dass das Maximum Integer.MAX_VALUE - 2 oder (2 ^ 31) - 3 ist
PS Ich bin nicht sicher , warum mein StringBuilder
ausgereizt an , 1207959550
während meine char[]
ausgereizt an (2 ^ 31) -3. Es scheint, dass AbstractStringBuilder
die Größe seines internen verdoppelt char[]
, um es zu vergrößern, so dass wahrscheinlich das Problem verursacht.
Der Rückgabetyp der length () -Methode der String-Klasse ist int .
public int length ()
Siehe http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length ()
Der Maximalwert von int ist also 2147483647 .
Die Zeichenfolge wird intern als Zeichenarray betrachtet. Die Indizierung erfolgt also innerhalb des maximalen Bereichs. Dies bedeutet, dass wir das 2147483648-Mitglied nicht indizieren können. Die maximale Länge von String in Java beträgt also 2147483647.
Der primitive Datentyp int beträgt in Java 4 Byte (32 Bit). Da 1 Bit (MSB) als Vorzeichenbit verwendet wird , ist der Bereich auf -2 ^ 31 bis 2 ^ 31-1 (-2147483648 bis 2147483647) beschränkt. Wir können keine negativen Werte für die Indizierung verwenden. Der Bereich, den wir verwenden können, liegt offensichtlich zwischen 0 und 2147483647.
Wie in der Antwort von Takahiko Kawasaki erwähnt , repräsentiert Java Unicode-Strings in Form von modifiziertem UTF-8 und in der JVM-Spec CONSTANT_UTF8_info Structure werden der Länge 2 Bytes zugewiesen (und nicht der Anzahl der Zeichen von String).
Um die Antwort zu erweitern , enthält die Methode der ASM-JVM-Bytecode- Bibliothek Folgendes :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);
}
}
...
}
Wenn die Codepunktzuordnung> 1 Byte ist, wird die encodeUTF8
Methode aufgerufen :
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 diesem Sinne beträgt die maximale Zeichenfolgenlänge 65535 Byte, dh die utf-8-Codierungslänge. und nicht char
zählen
Sie können den modifizierten Unicode-Codepunktbereich von JVM über den obigen utf8-Strukturlink finden.
String
theoretisch istInteger.MAX_VALUE
, scheint die Länge eines String-Literal in der Quelle auf nur 65535 Byte UTF-8-Daten begrenzt zu sein.