Почему == сравнения с 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 .

Здесь есть поразительная разница.

valueOf возвращает объект Integer , который может иметь свои значения, кэшированные между -128 и 127. Вот почему первое значение возвращает true – оно кэшировано, а второе значение возвращает false – 128 не является кешированным значением, поэтому вы получая два отдельных экземпляра Integer .

Важно отметить, что вы сравниваете ссылки с Integer#valueOf , и если вы сравниваете значение, которое больше, чем то, что поддерживает кеш, оно не будет равно true , даже если анализируемые значения эквивалентны (пример: Integer.valueOf(128) == Integer.valueOf(128) ). Вместо этого вы должны использовать equals() .

parseInt возвращает примитивный int . Вот почему третье значение возвращает true128 == 128 оценивается и, конечно же, true .

Теперь справедливая битка делает третий результат true :

  • Преобразование unboxing происходит в отношении используемого вами оператора эквивалентности и типов данных, а именно: int и Integer . Разумеется, вы получаете Integer от valueOf с правой стороны.

  • После преобразования вы сравниваете два примитивных значения int . Сравнение происходит так же, как вы ожидали бы этого в отношении примитивов, поэтому вы заканчиваете сравнение 128 и 128 .

Класс Integer имеет статический кеш, который хранит 256 специальных объектов Integer – по одному для каждого значения между -128 и 127. Учитывая это, рассмотрите разницу между этими тремя.

 new Integer(123); 

Это (очевидно) создает совершенно новый объект Integer .

 Integer.parseInt("123"); 

Это возвращает примитивное значение int после parsingа String .

 Integer.valueOf("123"); 

Это сложнее, чем другие. Он начинается с parsingа 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 .

Позаботьтесь о возврате значений из этих методов. Метод valueOf возвращает экземпляр Integer:

 public static Integer valueOf(int i) 

Метод parseInt возвращает целочисленное значение (примитивный тип):

 public static int parseInt(String s) throws NumberFormatException 

Объяснение для сравнения:

Чтобы сохранить память, два экземпляра объектов-оболочек всегда будут ==, когда их примитивные значения одинаковы:

  • логический
  • Байт
  • Символ от \ u0000 до \ u007f (7f равен 127 в десятичной форме)
  • Короткие и целочисленные от -128 до 127

Когда == используется для сравнения примитива с оберткой, shell будет развернута, и сравнение будет примитивным для примитива.

В вашей ситуации (согласно приведенным выше правилам):

 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); } 

Если param является целым числом между IntegerCache.low (по умолчанию -128) и IntegerCache.high (вычисляется во время выполнения с минимальным значением 127), возвращается возвращаемый (кэшированный) объект. Поэтому, когда вы используете параметр 127 в качестве параметра, вы получаете две ссылки на один и тот же кешированный объект и получаете значение true при сравнении ссылок.

Целочисленные объекты кэшируются между -128 и 127 из 256 Integer

Вы не должны сравнивать ссылки на объекты с == или ! = . Вы должны использовать. equals (..) вместо этого или лучше – используйте примитив int, а не Integer.

parseInt : анализирует строковый аргумент как десятичное целое число. Символы в строке должны быть десятичными цифрами, за исключением того, что первый символ может быть знаком ASCII минус ‘-‘ (‘\ u002D’), чтобы указать отрицательное значение. Полученное целочисленное значение возвращается точно так же, как если бы аргумент и radix 10 были указаны как аргументы метода parseInt (java.lang.String, int).

valueOf Возвращает целочисленный объект, удерживающий значение, извлеченное из указанной строки, когда выполняется синтаксический анализ с основанием, заданным вторым аргументом. Первый аргумент интерпретируется как представляющее целое число со знаком в радиусе, заданном вторым аргументом, точно так же, как если бы аргументы были переданы методу 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

Давайте будем гением компьютера.