Почему поведение пула констант Integer изменяется на 127?
Я не могу понять, как работает пул констант Java для целых чисел.
Я понимаю поведение строк и, следовательно, могу оправдать себя тем, что то же самое можно сказать и о целочисленных константах.
Итак, для целых
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?????
Может кто-нибудь помочь мне понять это?
4 ответа
Нет, пул констант для чисел не работает так же, как для строк. Для строк интернируются только константы времени компиляции, тогда как для типов-оболочек для целочисленных типов любая операция бокса всегда будет использовать пул, если она применима для этого значения. Так, например:
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
Если значение p в штучной упаковке является истинным, ложным, байтом или символом в диапазоне от \u0000 до \u007f, или целым или коротким числом от -128 до 127 (включительно), то пусть r1 и r2 будут результатами любые два преобразования бокса р. Это всегда тот случай, когда r1 == r2.
В идеале, бокс заданного примитивного значения p всегда будет давать одинаковую ссылку. На практике это может оказаться невозможным при использовании существующих методов реализации. Приведенные выше правила являются прагматическим компромиссом. Последнее предложение выше требует, чтобы определенные общие значения всегда помещались в неразличимые объекты. Реализация может кэшировать их, лениво или охотно. Для других значений эта формулировка не допускает никаких предположений об идентичности значений в штучной упаковке со стороны программиста. Это позволит (но не требует) совместного использования некоторых или всех этих ссылок.
Это гарантирует, что в большинстве распространенных случаев поведение будет желательным без наложения чрезмерного снижения производительности, особенно на небольших устройствах. Реализации с меньшим объемом памяти могут, например, кэшировать все значения типа char и short, а также значения типа int и long в диапазоне от -32K до +32K.
Java поддерживает пул Integer из -128
в 127
Объявление Integer, как показано ниже
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
между этим диапазоном.
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
Короче, новые версии Java кеша Integer находятся в диапазоне от -128 до 127 (256 значений). Смотри сюда