Während die Länge von a Stringtheoretisch ist Integer.MAX_VALUE, scheint die Länge eines String-Literal in der Quelle auf nur 65535 Byte UTF-8-Daten begrenzt zu sein.
200_erfolg
Antworten:
169
Unter Berücksichtigung der StringKlasse lengthMethode 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.)
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 nKomponenten enthält, nist dies die
Länge des Arrays. Auf die Komponenten des Arrays wird mit ganzzahligen Indizes von 0bis n - 1einschließlich verwiesen .
Darüber hinaus muss die Indizierung nach intWerten erfolgen, wie in Abschnitt 10.4 erwähnt :
Arrays müssen durch intWerte indiziert werden.
Daher scheint es, dass die Grenze tatsächlich ist 2^31 - 1, da dies der Maximalwert für einen nichtnegativen intWert ist.
Es wird jedoch wahrscheinlich andere Einschränkungen geben, z. B. die maximal zuweisbare Größe für ein Array.
Großartige Antwort Mann! Ich habe mir den Quellcode von String.java angesehen und es ist richtig, 'count' ist die int-Variable, die die Länge des char-Arrays zurückgibt, und das char-Array wird in der 'value'-Variablen gespeichert (als char []) dass die String-Größe etwa 2 GB betragen könnte. Natürlich kann es Einschränkungen geben, eine solche Speichergröße zuzuweisen. Vielen Dank!
Taichi
5
Ich habe gerade versucht, ein String-Literal in einem Hallo-Welt-Java-Programm zu definieren, das länger als 65546 war. Es javacgibt einen Fehler, dass dieses Literal zu lang ist:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
Dlamblin
2
@dlamblin: Das klingt nach einer Einschränkung javacfür StringLiterale (keine StringObjekte), da ich Stringin der Java-Sprachspezifikation und der JVM-Spezifikation keinen Verweis auf Größenbeschränkungen für Literale finden kann . Ich habe versucht, ein StringLiteral 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.lengthmehr als 100.000 hatte.)
Coobird
3
@Premraj Es war vor drei Jahren, also musste ich darüber nachdenken. ;) Was ich meinte, war; Um eine Zeichenfolge mit maximaler Größe zu erstellen, benötigen Sie viel Speicher, möglicherweise mehr als Sie ohnehin haben. Sie benötigen zwei Bytes pro Zeichen ~ 4 GB, aber Sie müssen dies aus einem StringBuilder oder char [] erstellen, was bedeutet, dass Sie zwei weitere Bytes pro Zeichen benötigen, um es überhaupt zu erstellen, dh weitere ~ 4 GB (zumindest vorübergehend)
Peter Lawrey
25
java.io.DataInput.readUTF()und java.io.DataOutput.writeUTF(String)sagen, dass ein StringObjekt 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 DataInputund verwendet wird DataOutput.
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, intbedeutet nicht immer, dass der zulässige Maximalwert ist Integer.MAX_VALUE. Stattdessen wird in den meisten Fällen intnur aus Leistungsgründen gewählt. Die Java-Sprachspezifikation besagt, dass Ganzzahlen, deren Größe kleiner als die von intist, intvor der Berechnung konvertiert werden (wenn mein Speicher mir richtig dient), und es ist ein Grund zu wählen, intwenn 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 StringObjekt ist.
StringObjekte können zur Laufzeit möglicherweise viel mehr Zeichen enthalten. Wenn Sie jedoch StringObjekte mit DataInputund DataOutputSchnittstellen verwenden möchten , ist es besser, zu lange StringObjekte 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 =newStringBuilder();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 =newchar[Integer.MAX_VALUE - i];Arrays.fill(array,'a');String string =newString(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:2147483647Last:0Requested array size exceeds VM limit
Last:2147483646Last:1Java heap space
Last:2147483645Last:2
Es scheint also, dass das Maximum Integer.MAX_VALUE - 2 oder (2 ^ 31) - 3 ist
PS Ich bin nicht sicher , warum mein StringBuilderausgereizt an , 1207959550während meine char[]ausgereizt an (2 ^ 31) -3. Es scheint, dass AbstractStringBuilderdie Größe seines internen verdoppelt char[], um es zu vergrößern, so dass wahrscheinlich das Problem verursacht.
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.
publicByteVector putUTF8(finalString stringValue){int charLength = stringValue.length();if(charLength >65535){// If no. of characters> 65535, than however UTF-8 encoded length, wont fit in 2 bytes.thrownewIllegalArgumentException("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 encodeUTF8Methode aufgerufen :
In diesem Sinne beträgt die maximale Zeichenfolgenlänge 65535 Byte, dh die utf-8-Codierungslänge. und nicht charzä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.Antworten:
Unter Berücksichtigung der
String
Klasselength
Methode gibt einint
, die maximale Länge , die durch das Verfahren zurückgeführt werden würde , wäreInteger.MAX_VALUE
, das ist2^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ürString
s implementiert wird ) wird in Kapitel 10: Arrays der Java-Sprachspezifikation, Java SE 7 Edition , Folgendes angegeben:Darüber hinaus muss die Indizierung nach
int
Werten erfolgen, wie in Abschnitt 10.4 erwähnt :Daher scheint es, dass die Grenze tatsächlich ist
2^31 - 1
, da dies der Maximalwert für einen nichtnegativenint
Wert ist.Es wird jedoch wahrscheinlich andere Einschränkungen geben, z. B. die maximal zuweisbare Größe für ein Array.
quelle
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ürString
Literale (keineString
Objekte), da ichString
in der Java-Sprachspezifikation und der JVM-Spezifikation keinen Verweis auf Größenbeschränkungen für Literale finden kann . Ich habe versucht, einString
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 LiteralString.length
mehr als 100.000 hatte.)java.io.DataInput.readUTF()
undjava.io.DataOutput.writeUTF(String)
sagen, dass einString
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 mitDataInput
und verwendet wirdDataOutput
.Darüber hinaus Die Spezifikation
CONSTANT_Utf8_info
definiert Gefunden in der Java Virtual Machine Spezifikation die Struktur wie folgt.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 istInteger.MAX_VALUE
. Stattdessen wird in den meisten Fällenint
nur aus Leistungsgründen gewählt. Die Java-Sprachspezifikation besagt, dass Ganzzahlen, deren Größe kleiner als die vonint
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 jedochString
Objekte mitDataInput
undDataOutput
Schnittstellen verwenden möchten , ist es besser, zu langeString
Objekte zu vermeiden . Ich habe diese Einschränkung festgestellt, als ich Objective-C-Äquivalente vonDataInput.readUTF()
und implementiert habeDataOutput.writeUTF(String)
.quelle
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.quelle
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:
Dies druckt:
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:
Welche Drucke:
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 meinechar[]
ausgereizt an (2 ^ 31) -3. Es scheint, dassAbstractStringBuilder
die Größe seines internen verdoppeltchar[]
, um es zu vergrößern, so dass wahrscheinlich das Problem verursacht.quelle
anscheinend ist es an ein int gebunden, das 0x7FFFFFFF (2147483647) ist.
quelle
Der Rückgabetyp der length () -Methode der String-Klasse ist int .
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.
quelle
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
Wenn die Codepunktzuordnung> 1 Byte ist, wird die
encodeUTF8
Methode aufgerufen :In diesem Sinne beträgt die maximale Zeichenfolgenlänge 65535 Byte, dh die utf-8-Codierungslänge. und nicht
char
zählenSie können den modifizierten Unicode-Codepunktbereich von JVM über den obigen utf8-Strukturlink finden.
quelle