Почему сравнения == с 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
,
5 ответов
Здесь есть разительная разница.
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
:
Преобразование распаковки происходит в отношении оператора эквивалентности, который вы используете, и ваших типов данных, а именно:
int
а такжеInteger
, Вы получаетеInteger
отvalueOf
с правой стороны, конечно.После преобразования вы сравниваете два примитива
int
ценности. Сравнение происходит так же, как вы ожидаете, что касается примитивов, поэтому вы сравниваете128
а также128
,
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");
Это возвращает истину, потому что 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
,
Позаботьтесь о возврате значений из этих методов. Метод valueOf возвращает экземпляр Integer:
public static Integer valueOf(int i)
Метод parseInt возвращает целочисленное значение (тип примитива):
public static int parseInt(String s) throws NumberFormatException
Объяснение для сравнения:
В целях экономии памяти два экземпляра объектов-оболочек всегда будут ==, если их примитивные значения одинаковы:
- логический
- Байт
- Символ от \u0000 до \u007f (7f - 127 в десятичном виде)
- Short и Integer от -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.
Чтобы дополнить данные ответы, также обратите внимание на следующее:
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);
}
Если параметр является целым числом между IntegerCache.low
(по умолчанию -128) и IntegerCache.high
(вычисляется во время выполнения с минимальным значением 127), затем возвращается предварительно выделенный (кэшированный) объект. Поэтому, когда вы используете 127 в качестве параметра, вы получаете две ссылки на один и тот же кэшированный объект и получаете true
в сравнении ссылок.
Кэши целых объектов между -128 и 127 из 256 Integer
Вы не должны сравнивать ссылки на объекты с == или ! =. Вы должны использовать.равно (..) вместо этого или лучше - используйте примитив 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 - основа, которая будет использоваться при интерпретации
так что если вы равны Integer.valueOf()
для целого числа между
От -128 до 127 возвращает true в вашем состоянии
за lesser than
-128 и greater than
127 это дает false