Я только что видел код, похожий на этот:
public class Scratch
{
public static void main(String[] args)
{
Integer a = 1000, b = 1000;
System.out.println(a == b);
Integer c = 100, d = 100;
System.out.println(c == d);
}
}
При запуске этот блок кода распечатает:
false
true
Я понимаю, почему первый false
: потому что два объекта являются отдельными объектами, поэтому ==
сравнивает ссылки. Но я не могу понять, почему возвращается второй оператор true
? Есть ли какое-то странное правило автобокса, которое срабатывает, когда значение Integer находится в определенном диапазоне? Что тут происходит?
java
autoboxing
Joel
источник
источник
Ответы:
true
Линия фактически гарантируется спецификацией языка. Из раздела 5.1.7 :Обсуждение продолжается, предполагая, что, хотя ваша вторая строка вывода гарантирована, первая - нет (см. Последний абзац, цитируемый ниже):
источник
valueOf
метода класса бокса (например,Integer.valueOf(int)
). Интересно, что JLS определяет точное обессахаривание при распаковке с использованиемintValue()
и др., Но не обессахаривание при распаковке.Integer
кроме как через официальныйpublic
API, то есть через вызовintValue()
. Но есть и другие возможные способы получитьInteger
экземпляр дляint
значения, например, компилятор может сгенерировать код, сохраняя и повторно используя ранее созданныеInteger
экземпляры.Вывод:
Да, первый вывод создается для сравнения ссылок; 'a' и 'b' - это две разные ссылки. В пункте 1 фактически создаются две ссылки, которые похожи на -
Второй вывод создается из-за того, что
JVM
пытается сохранить память, когда значениеInteger
попадает в диапазон (от -128 до 127). В пункте 2 не создается новая ссылка типа Integer для 'd'. Вместо создания нового объекта для ссылочной переменной целочисленного типа 'd' ему назначается только ранее созданный объект, на который ссылается 'c'. Все это делаетJVM
.Эти правила экономии памяти не только для Integer. в целях экономии памяти два экземпляра следующих объектов-оболочек (при создании с помощью упаковки) всегда будут ==, где их примитивные значения одинаковы -
\u007f
(7f - 127 в десятичной системе)источник
Long
также имеет кеш с тем же диапазоном, что иInteger
.Целочисленные объекты в некотором диапазоне (я думаю, может быть, от -128 до 127) кэшируются и используются повторно. Целые числа вне этого диапазона каждый раз получают новый объект.
источник
java.lang.Integer.IntegerCache.high
свойства. Интересно, что у Лонга такой возможности нет.Да, есть странное правило автобокса, которое срабатывает, когда значения находятся в определенном диапазоне. Когда вы назначаете константу переменной Object, ничто в определении языка не говорит о необходимости создания нового объекта . Он может повторно использовать существующий объект из кеша.
Фактически, для этой цели JVM обычно хранит кеш небольших целых чисел, а также такие значения, как Boolean.TRUE и Boolean.FALSE.
источник
Я предполагаю, что Java хранит кеш небольших целых чисел, которые уже «упакованы», потому что они очень распространены, и это экономит чертовски много времени на повторное использование существующего объекта, чем на создание нового.
источник
Это интересный момент. В книге « Эффективная Java» предлагается всегда переопределять равенства для ваших собственных классов. Кроме того, чтобы проверить равенство двух экземпляров объекта класса java, всегда используйте метод equals.
возвращает:
источник
В Java бокс работает в диапазоне от -128 до 127 для целого числа. Когда вы используете числа в этом диапазоне, вы можете сравнить его с оператором ==. Для объектов Integer за пределами диапазона вы должны использовать equals.
источник
Прямое присвоение целочисленного литерала целочисленной ссылке - это пример автоматической упаковки, когда буквальное значение в код преобразования объекта обрабатывается компилятором.
Итак, на этапе компиляции компилятор преобразуется
Integer a = 1000, b = 1000;
вInteger a = Integer.valueOf(1000), b = Integer.valueOf(1000);
.Таким образом, это
Integer.valueOf()
метод, который фактически дает нам целочисленные объекты, и если мы посмотрим на исходный кодInteger.valueOf()
метода, мы ясно увидим, что метод кэширует целочисленные объекты в диапазоне от -128 до 127 (включительно).Таким образом, вместо создания и возврата новых целочисленных объектов
Integer.valueOf()
метод возвращает целочисленные объекты из внутреннего,IntegerCache
если переданный литерал int больше -128 и меньше 127.Java кэширует эти целочисленные объекты, потому что этот диапазон целых чисел часто используется в повседневном программировании, что косвенно экономит память.
Кеш инициализируется при первом использовании, когда класс загружается в память из-за статического блока. Максимальным диапазоном кеша можно управлять с помощью
-XX:AutoBoxCacheMax
опции JVM.Такое кеширование не применимо только для объектов типа Integer, как и Integer.IntegerCache, который у нас также есть
ByteCache, ShortCache, LongCache, CharacterCache
дляByte, Short, Long, Character
соответственно.Вы можете прочитать больше в моей статье Java Integer Cache - Почему Integer.valueOf (127) == Integer.valueOf (127) Is True .
источник
В Java 5 была представлена новая функция для экономии памяти и повышения производительности при обработке объектов целочисленного типа. Целочисленные объекты кэшируются внутри и повторно используются через те же объекты, на которые есть ссылки.
Это применимо для целочисленных значений в диапазоне от –127 до +127 (максимальное целочисленное значение).
Это целочисленное кеширование работает только при автобоксировании. Целочисленные объекты не будут кэшироваться, если они построены с использованием конструктора.
Для получения более подробной информации перейдите по ссылке ниже:
Целочисленный кэш в деталях
источник
Если мы проверим исходный код объекта
Integer
obeject, мы найдем источникvalueOf
метода примерно так:что может объяснить, почему
Integer
объекты, которые находятся в диапазоне от -128 (Integer.low
) до 127 (Integer.high
), являются одними и теми же ссылочными объектами во время автобокса. И мы видим, что существует класс, которыйIntegerCache
заботится оInteger
массиве кеша, который является частным статическим внутренним классомInteger
класса.Есть еще один интересный пример, который может помочь нам разобраться в этой странной ситуации:
источник