Почему поведение пула констант Integer изменяется на 127?

Я не могу понять, как работает Java Constant Pool для Integer.

Я понимаю поведение строк и, следовательно, могу оправдать себя, что это тот же случай с константами Integer.

Итак, для целых чисел

Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1==i2); // True

&

Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1==i2); // False

До сих пор все идет мне в голову.

То, что я не могу переварить, это ведет себя по-разному, когда я увеличиваю целое число с 127. Это поведение меняется после 127, ниже - фрагмент кода

Integer i1 = 128;
Integer i2 = 128;
System.out.println(i1==i2); // False. WHY?????

Может кто-нибудь помочь мне понять это?

Ответ 1

Нет, постоянный пул для чисел не работает так же, как для строк. Для строк используются только константы времени компиляции, тогда как для типов оберток для целых типов любая операция по боксу всегда будет использовать пул, если она применима для этого значения. Так, например:

int x = 10;
int y = x + 1;
Integer z = y; // Not a compile-time constant!
Integer constant = 11;
System.out.println(z == constant); // true; reference comparison

JLS гарантирует небольшой диапазон объединенных значений, но реализации могут использовать более широкий диапазон, если они пожелают.

Обратите внимание, что, хотя это не гарантировано, каждая реализация, на которую я смотрел, использует Integer.valueOf для выполнения операций в боксе - так что вы можете получить такой же эффект без помощи языка:

Integer x = Integer.valueOf(100);
Integer y = Integer.valueOf(100);
System.out.println(x == y); // true

Из раздел 5.1.7 JLS:

Если значение p в боксе равно true, false, байту или char в диапазоне от \u0000 до\u007f или int или коротком числе между -128 и 127 (включительно), тогда пусть r1 и r2 - результаты любых двух бокс-преобразований p. Всегда бывает, что r1 == r2.

В идеале, бокс данного примитивного значения p всегда будет давать идентичную ссылку. На практике это может оказаться невозможным с использованием существующих методов внедрения. Правила выше - прагматичный компромисс. Последнее заключительное предложение требует, чтобы определенные общие значения всегда помещались в неразличимые объекты. Реализация может кэшировать эти, лениво или нетерпеливо. Для других значений эта формулировка запрещает любые предположения о идентичности вложенных значений в части программиста. Это позволило бы (но не требовать) совместного использования некоторых или всех этих ссылок.

Это гарантирует, что в большинстве распространенных случаев поведение будет желательным, не налагая чрезмерного штрафа за производительность, особенно на небольшие устройства. Менее ограниченные памятью реализации могут, например, кэшировать все char и короткие значения, а также значения int и long в диапазоне от -32K до + 32K.

Ответ 2

Java поддерживает пул Integer от -128 до 127

Объявление целого, как показано ниже

Integer i1 = 127;

Результаты в

Integer i1 = Integer.valueOf(127);

Итак, что на самом деле происходит для первого случая -

Integer i1 = 127;<---Integer.valueOf(127);
Integer i2 = 127;<---Integer.valueOf(127);<---Same reference as first

Из исходного кода метода Integer для класса valueOf

public static Integer valueOf(int i) {
    if(i >= -128 && i <= IntegerCache.high)
        return IntegerCache.cache[i + 128];
    else
        return new Integer(i);
}

Итак, вы получаете такую ​​же ссылку, если значение находится между -128 и 127, и вы вызываете valueOf иначе он просто возвращает new Integer(i)

И поскольку ссылка такая же, ваш оператор == работает для целых чисел, возвращаемых valueOf между этим диапазоном.

Ответ 3

Java кэширует целые объекты в диапазоне -128 to 127. Поэтому, когда вы пытаетесь присвоить значение в этом диапазоне объекту wrapper, операция boxing вызовет метод Integer.valueOf и, в свою очередь, назначит ссылку на объект, уже находящийся в пуле.

С другой стороны, если вы присвоите значение вне этого диапазона ссылочному типу wrapper, Integer.valueOf создаст для этого значения новый объект Integer. И, следовательно, сравнение объектов reference для Integer, имеющих значение вне этого диапазона, даст вам false

Итак,

Integer i = 127;  --> // Equivalent to `Integer.valueOf(127)`
Integer i2 = 127;

// Equivalent to `Integer.valueOf(128)`
// returns `new Integer(128)` for value outside the `Range - [-128, 127]`
Integer i3 = 128; 
Integer i4 = 128;

System.out.println(i == i2); // true, reference pointing to same literal
System.out.println(i3 == i4); // false, reference pointing to different objects

Но при создании целых экземпляров с помощью оператора new в куче будет создан новый объект. Итак,

Integer i = new Integer(127);
Integer i2 = new Integer(127);

System.out.println(i == i2); // false