Почему 128==128 равно false, но 127==127 равно true при сравнении целочисленных оболочек в Java?
-
19-09-2019 - |
Вопрос
class D {
public static void main(String args[]) {
Integer b2=128;
Integer b3=128;
System.out.println(b2==b3);
}
}
Выходной сигнал:
false
class D {
public static void main(String args[]) {
Integer b2=127;
Integer b3=127;
System.out.println(b2==b3);
}
}
Выходной сигнал:
true
Примечание:Числа от -128 до 127 являются истинными.
Решение
Когда вы компилируете числовой литерал в Java и присваиваете его целому числу (с заглавной буквы), I
) компилятор выдает:
Integer b2 =Integer.valueOf(127)
Эта строка кода также генерируется при использовании автобокса.
valueOf
реализован таким образом, что определенные числа «объединяются» и возвращают один и тот же экземпляр для значений меньше 128.
Из исходного кода Java 1.6, строка 621:
public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
Значение high
можно настроить на другое значение с помощью системного свойства.
-Djava.lang.Integer.IntegerCache.high=999
Если вы запустите программу с этим системным свойством, она выдаст true!
Очевидный вывод:никогда не полагайтесь на то, что две ссылки идентичны, всегда сравнивайте их с .equals()
метод.
Так b2.equals(b3)
выведет true для всех логически равных значений b2,b3.
Обратите внимание, что Integer
кэш существует не по соображениям производительности, а скорее для соответствия JLS, раздел 5.1.7;Идентичность объекта должна быть указана для значений от -128 до 127 включительно.
Целое число#значениеOf(целое) также документирует это поведение:
этот метод, вероятно, даст значительно лучшую производительность по пространству и времени за счет кэширования часто запрашиваемых значений.Этот метод всегда кэширует значения в диапазоне от -128 до 127 включительно и может кэшировать другие значения за пределами этого диапазона.
Другие советы
Автоматическое заполнение кэшей -128-127.Это указано в JLS (5.1.7).
Если значение p в ячейку помещаются значения true, false, байт, символ в диапазоне от \ u0000 до \u007f или int или короткое число от -128 до 127, тогда пусть r1 и r2 являются результатами любых двух боксирующих преобразований из п.Это всегда так, что r1 == r2.
Простое правило, которое следует помнить при работе с объектами, гласит: используйте .equals
если вы хотите проверить, являются ли два объекта "равными", используйте ==
когда вы хотите посмотреть, указывают ли они на один и тот же экземпляр.
Использование примитивных типов данных, целых чисел, в обоих случаях дало бы ожидаемый результат true.
Однако, поскольку вы используете целочисленные объекты, оператор == имеет другое значение.
В контексте объектов == проверяет, ссылаются ли переменные на одну и ту же ссылку на объект.
Чтобы сравнить значения объектов, вы должны использовать метод equals() Например.
b2.equals(b1)
который будет указывать, меньше ли b2, чем b1, больше или равно (подробности см. в API)
Это связано с оптимизацией памяти в Java.
Для экономии памяти Java "повторно использует" все объекты-оболочки, значения которых попадают в следующие диапазоны:
Все логические значения (true и false)
Все байтовые значения
Все символьные значения от \u0000 до \u007f (т. е.от 0 до 127 в десятичной системе счисления)
Все короткие и целочисленные значения от -128 до 127.
Посмотрите на Integer.java: если значение находится между -128 и 127, он будет использовать кешированный пул, поэтому (Integer) 1 == (Integer) 1
пока (Integer) 222 != (Integer) 222
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Я написал следующее, поскольку эта проблема характерна не только для Integer.Мой вывод таков: чаще всего, если вы используете API неправильно, вы все равно увидите неправильное поведение.Используйте его правильно, и вы увидите правильное поведение:
public static void main (String[] args) {
Byte b1=127;
Byte b2=127;
Short s1=127; //incorrect should use Byte
Short s2=127; //incorrect should use Byte
Short s3=128;
Short s4=128;
Integer i1=127; //incorrect should use Byte
Integer i2=127; //incorrect should use Byte
Integer i3=128;
Integer i4=128;
Integer i5=32767; //incorrect should use Short
Integer i6=32767; //incorrect should use Short
Long l1=127L; //incorrect should use Byte
Long l2=127L; //incorrect should use Byte
Long l3=13267L; //incorrect should use Short
Long l4=32767L; //incorrect should use Short
Long l5=2147483647L; //incorrect should use Integer
Long l6=2147483647L; //incorrect should use Integer
Long l7=2147483648L;
Long l8=2147483648L;
System.out.print(b1==b2); //true (incorrect) Used API correctly
System.out.print(s1==s2); //true (incorrect) Used API incorrectly
System.out.print(i1==i2); //true (incorrect) Used API incorrectly
System.out.print(l1==l2); //true (incorrect) Used API incorrectly
System.out.print(s3==s4); //false (correct) Used API correctly
System.out.print(i3==i4); //false (correct) Used API correctly
System.out.print(i5==i6); //false (correct) Used API correctly
System.out.print(l3==l4); //false (correct) Used API correctly
System.out.print(l7==l8); //false (correct) Used API correctly
System.out.print(l5==l6); //false (correct) Used API incorrectly
}