Подтвердить что ты не робот

Сколько объектов создается с помощью класса-оболочки Integer?

Integer i = 3; 
i = i + 1; 
Integer j = i; 
j = i + j; 

Сколько объектов создается в результате операторов в приведенном выше примере кода и почему? Есть ли IDE, в котором мы можем видеть, сколько объектов создано (возможно, в режиме отладки)?

4b9b3361

Ответ 1

Ответ, на удивление, равен нулю.

Все Integer от -128 до +127 предварительно вычисляются JVM.

Ваш код создает ссылки на эти существующие объекты.

Ответ 2

Строго правильный ответ заключается в том, что количество созданных объектов Integer неопределенно. Это может быть от 0 до 3 или 256 1 или даже больше 2 в зависимости от

  • платформа Java 3,
  • выполняется ли это первый раз, когда этот код выполняется, и
  • (потенциально), работает ли другой код, который полагается на бокс для значений int перед ним 4.

Значения Integer для -128 до 127 не обязательно должны быть предварительно вычислены. Фактически, JLS 5.1.7, в котором указано, что Бокс конвертирует это:

Если значение p, помещенное в ячейку, является целым литералом типа int между -128 и 127 включительно (§3.10.1)... тогда пусть a и b - результаты любых двух бокс-преобразований p. Всегда бывает, что a == b.

Следует отметить две вещи:

  • JLS требует только этого для → литералов < <.
  • JLS не требует надежного кэширования значений. Ленивое кэширование также удовлетворяет поведенческим требованиям JLS.

Даже javadoc для Integer.valueof(int) не указывает, что результаты кэшируются с нетерпением.

Если мы рассмотрим исходный код Java SE для java.lang.Integer из Java с 6 по 8, ясно, что текущая стратегия реализации Java SE заключается в прекомпутете значения. Однако по разным причинам (см. Выше) все еще недостаточно, чтобы позволить нам дать определенный ответ на вопрос "сколько объектов".


1 - Это может быть 256, если выполнение вышеуказанного кода запускает инициализацию класса для Integer в версии Java, где кеш с нетерпением инициализируется во время инициализации класса.

2 - Это может быть даже больше, если кеш больше, чем требуется спецификация JVM. Размер кеша может быть увеличен с помощью опции JVM в некоторых версиях Java.

3 - Помимо общего подхода платформы к внедрению бокса, компилятор мог заметить, что некоторые или все вычисления могут быть выполнены во время компиляции или полностью оптимизированы.

4 - такой код может вызвать либо ленивую, либо желаемую инициализацию цельного кеша.

Ответ 3

Прежде всего: ответ, который вы ищете, это 0, как уже упоминалось ранее.

Но отпустите немного глубже. Как сказал Стивен, это зависит от времени его исполнения. Поскольку кеш фактически инициализирован.

Если вы посмотрите на документацию java.lang.Integer.IntegerCache:

Кэш инициализируется при первом использовании.

Это означает, что если вы впервые вызываете любое целое число, которое вы на самом деле создаете:

  • 256 целых объектов (или более: см. ниже)
  • 1 Объект для массива для хранения целых чисел
  • Пусть игнорируют объекты, необходимые для хранения класса (и методов/полей). Они все равно хранятся в метапассе.

Во второй раз вы вызываете их, вы создаете 0 объектов.


Все становится более забавным, когда вы делаете цифры немного выше. Например. в следующем примере:

Integer i = 1500; 

Допустимыми параметрами являются: 0, 1 или любое число от 1629 до 2147483776 (на этот раз только подсчет созданных Целочисленных значений. Зачем? Ответ приведен в следующем предложении определения Integer-Cache:

Размер кеша может управляться с помощью опции -XX: AutoBoxCacheMax =.

Таким образом, вы действительно можете изменить размер кэша, который был реализован.

Это означает, что вы можете связаться с вышеприведенной строкой:

  • 1: новый объект, если ваш кеш меньше 1500
  • 0: новые объекты, если ваш кеш был инициализирован раньше и содержит 1500
  • 1629: new (целое число). Объекты, если ваш кеш установлен ровно в 1500 и еще не инициализирован. Затем будут созданы значения Integer от -128 до 1500.
  • Как и в приведенном выше предложении, вы достигаете любого количества целых объектов здесь: Integer.MAX_VALUE + 129, который указан: 2147483776.

Имейте в виду: Это гарантируется только в Oracle/Open JDK (я проверил версии 7 и 8)

Как вы можете видеть, совершенно правильный ответ получить не так-то просто. Но просто сказать 0 сделает людей счастливыми.


PS: использование параметра menthoned может сделать следующее утверждение истинным: Integer.valueOf(1500) == 1500

Ответ 4

Компилятор распаковывает объекты Integer в int для выполнения арифметики с ними, вызывая intValue(), и он вызывает Integer.valueOf, чтобы вставить теги int, когда они назначены переменным Integer, поэтому ваш пример эквивалентен:

Integer i = Integer.valueOf(3);
i = Integer.valueOf(i.intValue() + 1);
Integer j = i;
j = Integer.valueOf(i.intValue() + j.intValue());

Назначение j = i; - это полностью нормальное назначение ссылки на объект, которое не создает новых объектов. Он не боксирует или не распаковывает, и не нужно, поскольку объекты Integer неизменяемы.

Метод valueOf позволяет кэшировать объекты и каждый раз возвращать один и тот же экземпляр для определенного числа. Требуется кэшировать ints -128 до +127. Для вашего стартового номера i = 3 все числа малы и гарантированно будут кэшироваться, поэтому количество объектов, которые необходимо создать, 0. Строго говоря, valueOf разрешено кэшировать экземпляры лениво, а не иметь их все предварительно сгенерированные, поэтому пример может все же создавать объекты в первый раз, но если код многократно запускается во время программы, количество объектов, созданных каждый раз на средние подходы 0.

Что делать, если вы начинаете с большего числа, чьи экземпляры не будут кэшироваться (например, i = 300)? Затем каждый вызов valueOf должен создать один новый объект Integer, а общее количество объектов, созданных каждый раз, 3.

(Или, может быть, это все равно ноль или, может быть, миллионы. Помните, что компиляторам и виртуальным машинам разрешено переписывать код по причинам производительности или реализации, если его поведение не изменилось иначе. Таким образом, он мог бы удалить вышеуказанный код полностью, если вы не используете результат. Или, если вы попытаетесь напечатать j, он может понять, что j всегда будет иметь такое же постоянное значение после вышеописанного фрагмента и, таким образом, выполнить всю арифметику во время компиляции, и напечатать постоянное значение. Фактический объем работы, выполняемой за кулисами для запуска вашего кода, всегда является детальностью реализации.)

Ответ 5

Вы можете отладить метод Integer.valueOf(int i), чтобы узнать его самостоятельно. Этот метод вызывается процессом автобоксинга компилятором.