Odpowiedzi:
Biorąc pod uwagę, że metoda Stringklasy lengthzwraca an int, maksymalna długość, jaka mogłaby zostać zwrócona przez metodę, wyniosłaby Integer.MAX_VALUE, czyli2^31 - 1 (lub około 2000000000).
Pod względem długości i indeksowania tablic (na przykład char[], co jest prawdopodobnie sposobem implementacji wewnętrznej reprezentacji danych dla Strings), Rozdział 10: Arrays of The Java Language Specification, Java SE 7 Edition mówi, co następuje:
Zmienne zawarte w tablicy nie mają nazw; zamiast tego odwołują się do nich wyrażenia dostępu do tablicy, które używają nieujemnych wartości indeksów całkowitych. Te zmienne nazywane są składnikami tablicy. Jeśli tablica zawiera
nkomponenty, mówimy, żenjest to długość tablicy; odwołania do składników tablicy są dokonywane za pomocą indeksów całkowitych od0don - 1włącznie.
Ponadto indeksowanie musi odbywać się według intwartości, jak wspomniano w sekcji 10.4 :
Tablice muszą być indeksowane według
intwartości;
Dlatego wydaje się, że granica jest rzeczywiście 2^31 - 1, ponieważ jest to maksymalna wartość dla intwartości nieujemnej .
Jednak prawdopodobnie będą inne ograniczenia, takie jak maksymalny rozmiar, jaki można przydzielić dla tablicy.
javacdaje błąd o tym, że ten literał jest za długi:javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
javacdla String literałów (nie Stringobiektów), ponieważ nie mogę znaleźć żadnego odniesienia do ograniczeń rozmiaru Stringliterałów w specyfikacji języka Java i specyfikacji JVM. Próbowałem utworzyć Stringliterał, który był większy niż 100 000 znaków, a kompilator Eclipse nie miał problemu z jego skompilowaniem. (A uruchomienie programu było w stanie wykazać, że literał miał String.lengthponad 100 000)
java.io.DataInput.readUTF()i java.io.DataOutput.writeUTF(String)powiedzmy, że Stringobiekt jest reprezentowany przez dwa bajty informacji o długości i zmodyfikowaną reprezentację UTF-8 każdego znaku w ciągu. Wynika z tego, że długość String jest ograniczona przez liczbę bajtów zmodyfikowanej reprezentacji ciągu UTF-8, gdy jest używany z DataInputiDataOutput .
Ponadto specyfikacjaCONSTANT_Utf8_info znaleziona w specyfikacji wirtualnej maszyny języka Java definiuje strukturę w następujący sposób.
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
Możesz zauważyć, że rozmiar „length” to dwa bajty .
To, że typem zwracanym przez daną metodę (np. String.length()) Jest int, nie zawsze oznacza, że dopuszczalna wartość maksymalna to Integer.MAX_VALUE. Zamiast tego w większości przypadków intjest wybierany tylko ze względu na wydajność. Specyfikacja języka Java mówi, że liczby całkowite, których rozmiar jest mniejszy niż rozmiar, intsą konwertowane intprzed obliczeniem (jeśli moja pamięć dobrze mi służy) i jest to jeden z powodów, dla których warto wybraćint gdy nie ma specjalnego powodu.
Maksymalna długość w czasie kompilacji wynosi maksymalnie 65536. Zwróć uwagę, że długość to liczba bajtów zmodyfikowanej reprezentacji UTF-8 , a nie liczba znaków w Stringobiekcie.
Stringobiekty mogą mieć znacznie więcej znaków w czasie wykonywania. Jeśli jednak chcesz używać Stringobiektów z interfejsami DataInputi DataOutput, lepiej unikać używania zbyt długich Stringobiektów. Znalazłem to ograniczenie, kiedy zaimplementowałem odpowiedniki Objective-C DataInput.readUTF()i DataOutput.writeUTF(String).
Ponieważ matryce muszą być indeksowane liczbami, maksymalna długość tablicy jest Integer.MAX_INT(2 31 1, lub 2 147 483 647). Oczywiście przy założeniu, że masz wystarczająco dużo pamięci, aby pomieścić tablicę o takim rozmiarze.
Mam komputer iMac z 2010 r. Z 8 GB pamięci RAM, działający pod kontrolą Eclipse Neon.2 Release (4.6.2) z Javą 1.8.0_25. Z argumentem VM -Xmx6g uruchomiłem następujący kod:
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());
To drukuje:
Requested array size exceeds VM limit
1207959550
Wydaje się więc, że maksymalny rozmiar tablicy to ~ 1,207,959,549. Wtedy zdałem sobie sprawę, że tak naprawdę nie obchodzi nas, czy Java zabraknie pamięci: po prostu szukamy maksymalnego rozmiaru tablicy (który wydaje się być gdzieś stałą zdefiniowaną). Więc:
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);
}
}
Które wydruki:
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
Wydaje się więc, że maksymalna wartość to Integer.MAX_VALUE - 2 lub (2 ^ 31) - 3
PS Nie jestem pewien, dlaczego StringBuilderosiągnąłem maksimum na, podczas 1207959550gdy mój char[]maksimum przy (2 ^ 31) -3. Wydaje się, że AbstractStringBuilderpodwaja rozmiar jej wnętrzachar[] aby go rozwijać, więc prawdopodobnie powoduje problem.
Typ Return metody length () klasy String to int .
public int length ()
Zobacz http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length ()
Zatem maksymalna wartość int to 2147483647 .
Łańcuch jest wewnętrznie traktowany jako tablica znaków, więc indeksowanie odbywa się w maksymalnym zakresie. Oznacza to, że nie możemy zindeksować 2147483648. elementu członkowskiego, więc maksymalna długość ciągu znaków w java to 2147483647.
Prymitywny typ danych int to 4 bajty (32 bity) w java. Ponieważ 1 bit (MSB) jest używany jako bit znaku , zakres jest ograniczony od -2 ^ 31 do 2 ^ 31-1 (od -2147483648 do 2147483647). Nie możemy używać wartości ujemnych do indeksowania, więc oczywiście zakres, którego możemy użyć, wynosi od 0 do 2147483647.
Jak wspomniano w odpowiedzi Takahiko Kawasaki , java reprezentuje łańcuchy Unicode w postaci zmodyfikowanego UTF-8, aw JVM-Spec CONSTANT_UTF8_info Structure 2 bajty są przydzielane do długości (a nie liczby znaków w łańcuchu).
Aby rozszerzyć odpowiedź, metoda biblioteki kodu bajtowego ASM jvm zawiera to: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);
}
}
...
}
Ale gdy mapowanie punktu kodu> 1 bajt, wywołuje encodeUTF8metodę:
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;
}
}
...
}
W tym sensie maksymalna długość łańcucha to 65535 bajtów, tj. Długość kodowania utf-8. and not charcount
Możesz znaleźć zmodyfikowany zakres punktów kodowych Unicode JVM, z powyższego linku utf8 struct.
Stringjest teoretycznieInteger.MAX_VALUE, długość literału ciągu w źródle wydaje się być ograniczona tylko do 65535 bajtów danych UTF-8.