Почему == сравнения с Integer.valueOf(String) дают разные результаты для 127 и 128?
Я понятия не имею, почему эти строки кода возвращают разные значения:
System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));
Вывод:
true
false
true
Почему первый возвращает true
, а второй возвращает false
? Есть ли что-то другое, чего я не знаю между 127
и 128
? (Конечно, я знаю, что 127
< 128
.)
Кроме того, почему третий возвращает true
?
Я прочитал ответ этого вопроса, но я до сих пор не понял, как он может вернуть true
, и почему код во второй строке возвращает false
.
Ответы
Ответ 1
Здесь поразительное различие.
valueOf
возвращает объект Integer
, который может иметь свои значения, кешированные между -128 и 127. Вот почему первое значение возвращает true
- оно кэшировано - и второе значение возвращает false
- 128 не является кешированным значением, поэтому вы получаете два отдельных экземпляра Integer
.
Важно отметить, что вы сравниваете ссылки с Integer#valueOf
, и если вы сравниваете значение, которое больше, чем поддерживает кеш, оно будет не > оцениваем до true
, даже если анализируемые значения эквивалентны (пример: Integer.valueOf(128) == Integer.valueOf(128)
). Вместо этого вы должны использовать equals()
.
parseInt
возвращает примитив int
. Вот почему оценивается третье значение true
- 128 == 128
и, конечно, true
.
Теперь справедливый бит делает третий результат true
:
-
Преобразование unboxing происходит в отношении используемого вами оператора эквивалентности и типов данных, а именно, int
и Integer
. Конечно, вы получаете Integer
от valueOf
с правой стороны.
-
После преобразования вы сравниваете два примитивных значения int
. Сравнение происходит так же, как вы ожидали бы этого в отношении примитивов, поэтому вы завершаете сравнение 128
и 128
.
Ответ 2
Класс Integer
имеет статический кеш, в котором хранится 256 специальных объектов Integer
- по одному для каждого значения между -128 и 127. Учитывая это, рассмотрите разницу между этими тремя.
new Integer(123);
Это (очевидно) делает новый объект Integer
.
Integer.parseInt("123");
Это возвращает примитивное значение int
после разбора String
.
Integer.valueOf("123");
Это сложнее, чем другие. Он начинается с разбора String
. Затем, если значение находится между -128 и 127, оно возвращает соответствующий объект из статического кеша. Если значение вне этого диапазона, то оно вызывает new Integer()
и передает значение, чтобы вы получили новый объект.
Теперь рассмотрим три выражения в вопросе.
Integer.valueOf("127")==Integer.valueOf("127");
Возвращает true, поскольку Integer
, значение которого 127, извлекается дважды из статического кеша и сравнивается с самим собой. Там задействуется только один объект Integer
, поэтому он возвращает true
.
Integer.valueOf("128")==Integer.valueOf("128");
Это возвращает false
, потому что 128 не находится в статическом кеше. Поэтому для каждой стороны равенства создается новый Integer
. Поскольку существует два разных объекта Integer
, а ==
для объектов возвращает true
, если обе стороны являются одним и тем же объектом, это будет false
.
Integer.parseInt("128")==Integer.valueOf("128");
Это сравнение примитивного значения int
128 слева, с вновь созданным объектом Integer
справа. Но, поскольку нет смысла сравнивать int
с Integer
, Java будет автоматически распаковывать Integer
перед выполнением сравнения; поэтому вы сравниваете int
с int
. Поскольку примитив 128 равен самому себе, это возвращает true
.
Ответ 3
Позаботьтесь о возврате значений из этих методов. Метод valueOf возвращает экземпляр Integer:
public static Integer valueOf(int i)
Метод parseInt возвращает целочисленное значение (примитивный тип):
public static int parseInt(String s) throws NumberFormatException
Объяснение для сравнения:
Чтобы сохранить память, два экземпляра объекты-оболочки всегда будут ==, когда их примитивные значения одинаковы:
- Boolean
- Байт
- Символ от \u0000 до\u007f (7f равен 127 в десятичной форме)
- Короткие и целые числа от -128 до 127
Когда == используется для сравнения примитива с оберткой, оболочка будет развернуто, и сравнение будет примитивным для примитивного.
В вашей ситуации (в соответствии с приведенными выше правилами):
Integer.valueOf("127")==Integer.valueOf("127")
В этом выражении сравниваются ссылки на один и тот же объект, поскольку он содержит значение Integer между -128 и 127, поэтому он возвращает true.
Integer.valueOf("128")==Integer.valueOf("128")
Это выражение сравнивает ссылки на разные объекты, поскольку они содержат значения Integer не в < -128, 127 > , поэтому он возвращает false.
Integer.parseInt("128")==Integer.valueOf("128")
Это выражение сравнивает примитивное значение (левая сторона) и ссылка на объект (правая сторона)
поэтому правая часть будет развернута, а его примитивный тип будет сравниваться с левым, чтобы он вернул true.
Ответ 4
В дополнение к данным ответам также обратите внимание на следующее:
public class Test {
public static void main(String... args) {
Integer a = new Integer(129);
Integer b = new Integer(129);
System.out.println(a == b);
}
}
Этот код также напечатает: false
Как пользователь Jay заявляет в комментарии для принятого ответа, следует соблюдать осторожность при использовании оператора ==
для объектов, здесь вы проверяете если обе ссылки одинаковы, а это не так, потому что они являются разными объектами, хотя они представляют одно и то же значение. Чтобы сравнить объекты, вы должны использовать метод equals
:
Integer a = new Integer(128);
Integer b = new Integer(128);
System.out.println(a.equals(b));
Это напечатает: true
Вы можете спросить, но тогда почему первая строка напечатала true
?. Проверяя исходный код метода Integer.valueOf
, вы можете увидеть следующее:
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
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);
}
Если param является целым числом между IntegerCache.low
(по умолчанию -128) и IntegerCache.high
(вычисленным во время выполнения с минимальным значением 127), возвращается возвращаемый (кэшированный) объект. Поэтому, когда вы используете параметр 127 в качестве параметра, вы получаете две ссылки на один и тот же кешированный объект и получаете true
в сравнении ссылок.
Ответ 5
Целочисленные объекты кэшируют между -128 и 127 из 256 Integer
Вы не должны сравнивать ссылки на объекты с == или !=. Вы должны использовать. equals (..), или лучше - используйте примитивный int, а не Integer.
parseInt: анализирует строковый аргумент как знаковое десятичное целое число. Символы в строке должны быть десятичными цифрами, за исключением того, что первый символ может быть знаком ASCII минус '-' ('\ u002D'), чтобы указать отрицательное значение. Полученное целочисленное значение возвращается точно так же, как если бы аргумент и радиус 10 были указаны как аргументы метода parseInt (java.lang.String, int).
valueOf
Возвращает объект Integer, удерживающий значение, извлеченное из указанной строки, когда выполняется синтаксическое разложение с основанием, заданным вторым аргументом. Первый аргумент интерпретируется как представляющее целое число со знаком в радиусе, заданном вторым аргументом, точно так же, как если бы аргументы были переданы методу parseInt (java.lang.String, int). Результатом является объект Integer, который представляет целочисленное значение, указанное в строке.
эквивалентно
new Integer(Integer.parseInt(s, radix))
radix - радиус, который будет использоваться при интерпретации s
поэтому, если вы равны Integer.valueOf()
для целого числа между
-128 - 127 возвращает true в вашем состоянии
для lesser than
-128 и greater than
127 он дает false