Відповіді:
Зважаючи на те, що String
клас ' length
return return an int
, максимальна довжина, яка повертається методом, буде такою Integer.MAX_VALUE
, яка становить 2^31 - 1
(або приблизно 2 млрд.)
З точки зору довжини і індексації масивів (наприклад char[]
, що, ймовірно , так як внутрішнє представлення даних здійснюється для String
с), Глава 10: Масиви з специфікації мови Java, Java SE 7 Видання говорить наступне:
Змінні, що містяться в масиві, не мають імен; натомість на них посилаються вирази доступу до масиву, які використовують негативні цілочисельні значення індексу. Ці змінні називаються компонентами масиву. Якщо масив має
n
компоненти, ми говоримо, щоn
це довжина масиву; компоненти масиву використовують цілочисельні індекси від0
доn - 1
включно.
Крім того, індексація повинна бути за int
значеннями, як зазначено у розділі 10.4 :
Масиви повинні бути індексовані
int
значеннями;
Отже, виявляється, що межа дійсно є 2^31 - 1
, оскільки це максимальне значення для негативного int
значення.
Однак, ймовірно, будуть інші обмеження, наприклад, максимальний розмір, який можна виділити для масиву.
javac
дає помилку з приводу того, що цей javac HelloWorld.java 2>&1|head -c 80 HelloWorld.java:3: constant string too long
javac
для String
літералів (не String
об'єктів), оскільки я не можу знайти жодних посилань на обмеження розміру для String
літералів у специфікації мови Java та специфікації JVM. Я спробував зробити String
літерал, розмір якого перевищує 100 000 символів, і у компілятора Eclipse не виникло проблем із його складанням. (І запуск програми зміг показати, що літерал мав String.length
більше 100 000.)
java.io.DataInput.readUTF()
і java.io.DataOutput.writeUTF(String)
кажуть, що String
об'єкт представлений двома байтами інформації про довжину та модифікованим представленням UTF-8 кожного символу в рядку. З цього випливає висновок, що довжина String обмежена кількістю байтів модифікованого представлення UTF-8 рядка при використанні з DataInput
і DataOutput
.
Крім того, специфікаціяCONSTANT_Utf8_info
знайденої у специфікації віртуальної машини Java визначає структуру наступним чином.
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
Ви можете встановити, що розмір "довжини" - два байти .
Те, що тип повернення певного методу (наприклад String.length()
) є int
не завжди, означає, що його максимальне значення є Integer.MAX_VALUE
. Натомість у більшості випадків int
вибирається саме з міркувань продуктивності. Спеціалізація мови Java говорить, що цілі числа, розмір яких менший, ніж розмір int
, перетворюються до int
обчислення (якщо моя пам'ять служить мені правильно), і це одна причина, щоб вибрати, int
коли немає особливої причини.
Максимальна довжина під час компіляції - не більше 65536. Зауважте ще раз, що довжина - це кількість байтів модифікованого представлення UTF-8 , а не кількість символів в String
об'єкті.
String
об'єкти можуть мати значно більше символів під час виконання. Тим НЕ менше, якщо ви хочете використовувати String
об'єкти з DataInput
і DataOutput
інтерфейсів, то краще не використовувати занадто довгі String
об'єкти. Я знайшов це обмеження, коли реалізував еквіваленти Objective-C DataInput.readUTF()
та DataOutput.writeUTF(String)
.
Оскільки масиви повинні бути проіндексовані цілими числами, максимальна довжина масиву становить Integer.MAX_INT
(2 31 -1, або 2 147 483 647). Це, припускаючи, що у вас є достатньо пам'яті, щоб вмістити масив такого розміру, звичайно.
У мене є iMac 2010 року з 8 ГБ оперативної пам’яті, працює Eclipse Neon.2 Release (4.6.2) з Java 1.8.0_25. З аргументом VM -Xmx6g я запустив наступний код:
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());
Це відбитки:
Requested array size exceeds VM limit
1207959550
Отже, здається, що максимальний розмір масиву становить ~ 1,207,959,549. Тоді я зрозумів, що нас насправді не хвилює, якщо у Java не вистачає пам’яті: ми просто шукаємо максимальний розмір масиву (який, здається, десь визначений). Так:
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);
}
}
Які відбитки:
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
Отже, здається, що макс є цілим. MAX_VALUE - 2, або (2 ^ 31) - 3
PS Я не впевнений, чому мій StringBuilder
максимізований, 1207959550
а мій - char[]
(2 ^ 31) -3. Здається, що AbstractStringBuilder
вдвічі збільшується внутрішній розмір, char[]
щоб виростити його, так що, ймовірно, викликає проблему.
Тип повернення методу length () класу String - це int .
загальна довжина int ()
Зверніться http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length ()
Отже максимальне значення int становить 2147483647 .
Рядок вважається внутрішнім масивом char, тому індексація проводиться в межах максимального діапазону. Це означає, що ми не можемо індексувати 2147483648-го члена. Отже, максимальна довжина String в Java - 2147483647.
Примітивний тип даних int становить 4 байти (32 біта) в java. Оскільки 1 біт (MSB) використовується як бітовий знак , діапазон обмежений в межах від -2 ^ 31 до 2 ^ 31-1 (-2147483648 до 2147483647). Ми не можемо використовувати негативні значення для індексації. Тому, очевидно, діапазон, який ми можемо використовувати, становить від 0 до 2147483647.
Як згадується у відповіді Такахіко Кавасакі , java представляє рядки Unicode у вигляді модифікованого UTF-8 та в структурі JVM-Spec CONSTANT_UTF8_info , 2 байти виділяються по довжині (а не кількість символів рядка).
Щоб розширити відповідь, на ASM JVM байт - коді бібліотеки 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);
}
}
...
}
Але коли зіставлення кодової точки> 1байт, він викликає encodeUTF8
метод:
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;
}
}
...
}
У цьому сенсі максимальна довжина рядка становить 65535 байт, тобто довжина кодування utf-8. і не char
рахувати.
Ви можете знайти модифікований діапазон кодових точок коду Unicode JVM за вказаною вище посиланням utf8.
String
теоретичноInteger.MAX_VALUE
, довжина рядкового літералу у джерелі обмежується лише 65535 байтом даних UTF-8.