Java: Почему постоянный пул поддерживается только для строковых значений?
Мой вопрос о java-интернате и постоянных пулах.
Java поддерживает пул констант для java.lang.String
, для умного использования памяти JVM и для этого java.lang.String сделан неизменным. Так почему же java не поддерживает постоянные пулы других неизменных типов, таких как Long, Integer, Char, Short? Разве это не спасет память тоже?
Мне известно о том, что целые числа объединяются для диапазона значений [-127, 127], хотя я не понимаю причину выбора этого диапазона.
Вот тестовый код, который я написал для проверки пула других неизменяемых типов данных.
public class PoolTest {
public static void main(String... args) {
// Pooling of Integer [-127, 127]
Integer x = 127, y = 127;
System.out.println("Integer:" + (x == y)); // prints true
x = 129;
y = 129;
System.out.println("Integer:" + (x == y)); // prints false
// Apparent pooling of short [-127, 127]
Short i = 127, j = 127;
System.out.println("Short: " + (i == j)); // prints true
i = 128;
j = 128;
System.out.println("Short: " + (i == j)); // prints false
// No pooling of long values
Long k = 10L, l = 10L;
System.out.println("Long: " + (i == j)); // prints false
k = 128L;
l = 128L;
System.out.println("Long: " + (i == j)); // prints false
}
}
2 ответа
Цель пула констант состоит в том, чтобы уменьшить накладные расходы памяти, необходимые для хранения нескольких копий констант. В случае String
s, JVM по своей природе обязана сохранять некоторый объект для каждой индивидуально различимой константы, а спецификация Java в основном говорит, что JVM должна дедуплицировать String
объекты при загрузке класса. Возможность ручного размещения String
в бассейне через intern
является недорогим и позволяет программистам идентифицировать конкретные значения (например, свойства), которые будут присутствовать на протяжении всей жизни программы, и сказать JVM убрать их с пути обычной сборки мусора.
Объединение числовых констант, с другой стороны, не имеет большого смысла по нескольким причинам:
- Наиболее конкретные числа никогда не используются в коде данной программы.
- Когда числа используются в коде, встраивание их в код в качестве непосредственных значений кода операции обходится дешевле с точки зрения памяти, чем попытка их объединить. Обратите внимание, что даже пустой
String
носит вокругchar[]
,int
для его длины, а другой для егоhashCode
, Для числа, напротив, требуется максимум восемь непосредственных байтов. - Начиная с последних версий Java,
Byte
,Short
, а такжеInteger
объекты от -128 до 127 (от 0 до 127 дляCharacter
) проповедуются по соображениям производительности, а не для экономии памяти. Этот диапазон предположительно был выбран, потому что это ранжированный байт со знаком, и он будет охватывать большое количество общих применений, хотя было бы нецелесообразно пытаться предварительно кэшировать очень большое количество значений.
В качестве заметки, имейте в виду, что правила интернирования были созданы задолго до введения автобоксирования и универсальных типов в Java 5, что значительно расширило степень использования классов-оболочек. Это увеличение использования привело Sun к добавлению этих общих значений в постоянный пул.
Ну, поскольку объекты String являются неизменяемыми, для нескольких ссылок безопасно "совместно использовать" один и тот же объект String.
public class ImmutableStrings
{
public static void main(String[] args)
{
String one = "str1";
String two = "str1";
System.out.println(one.equals(two));
System.out.println(one == two);
}
}
// Output
true
true
В таком случае на самом деле нет необходимости создавать два экземпляра идентичного объекта String. Если объект String может быть изменен, так как StringBuffer может быть изменен, мы были бы вынуждены создать два отдельных объекта. Но, поскольку мы знаем, что объекты String не могут изменяться, мы можем безопасно делиться объектом String между двумя ссылками String, одной и двумя. Это делается с помощью строкового литерального пула.
Вы можете перейти по этой ссылке, чтобы узнать в деталях.