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

Другие вопросы по тегам