Ответы:
Учитывая, что метод String
класса length
возвращает значение 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 представлением каждого символа в строке. Из этого следует, что длина строки ограничена количеством байтов модифицированного представления строки в UTF-8 при использовании с DataInput
и DataOutput
.
Кроме того, спецификацияCONSTANT_Utf8_info
найденной в спецификации виртуальной машины Java определяет структуру следующим образом.
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
Вы можете найти, что размер '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
Таким образом, кажется, что максимум - Integer.MAX_VALUE - 2 или (2 ^ 31) - 3
PS Я не уверен, почему мой StringBuilder
максимальный в 1207959550
то время как мой char[]
максимальный в (2 ^ 31) -3. Кажется, что AbstractStringBuilder
удваивает размер его внутреннего, char[]
чтобы увеличить его, так что, вероятно, вызывает проблему.
Тип возврата метода length () класса String - int .
public int length ()
См. Http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#length ()
Таким образом, максимальное значение int составляет 2147483647 .
Внутренняя строка считается массивом символов, поэтому индексация выполняется в максимальном диапазоне. Это означает, что мы не можем индексировать 2147483648-й член. Таким образом, максимальная длина строки в 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.