Как правильно сравнивать Integer в Java

Возможный дубликат:
целое число класс-оболочка и оператор == — где указывается поведение?

Я знаю, что целочисленный кеш Java используется в диапазоне от -127 до 128. Если

Integer i = 1;
Integer j = 1;

Integer m = 128;
Integer n = 128;

i == j // true
m == n // false

Но я столкнулся со странным явлением. Во-первых, посмотрите на следующий фрагмент.

List<CustomerNotice> customerNotice = findByExample(example); // use Hibernate findByExample method

for(CustomerNotice n : customerNotice){
if(n.getConfirmStatus() == NoticeConfirmStatus.UNCONFIRMED.getValue()){
    // do sth
}
}
public enum NoticeConfirmStatus{
UNCONFIRMED(1), //
CONFIRMED(2), //
FAILED_TO_CONFIRM(3); //


private final Integer value;

private NoticeConfirmStatus(Integer  value) {

    this.value = value;
}

public Integer getValue() {
    return this.value;
}
}

public class CustomerNotice {

@Column(name = "CONFIRM_STATUS")
private Integer confirmStatus;

public Integer getConfirmStatus() {
    return this.confirmStatus;
}
public void setConfirmStatus(Integer confirmStatus) {
    this.confirmStatus = confirmStatus;
}
}

Хотя выражение if не рекомендуется, я думаю, что оно вернет true, потому что n.getConfirmStatus()==1, но результат будет false. Я очень запутался.

Кроме того, theList<CustomerNotice> customerNotice получен методом Hibernate findByExample. Есть ли какая-то автоупаковка или новая операция при извлечении набора результатов?

Спасибо.


person Argun    schedule 15.12.2011    source источник
comment
Целочисленный кэш составляет от -128 до 128 по умолчанию. Системное свойство java.lang.Integer.IntegerCache.high может изменить конечный номер этого кеша на что-то другое (см. это). Не полагайтесь на целочисленный кеш вообще.   -  person prunge    schedule 15.12.2011
comment
Диапазон по умолчанию — от -128 до 127, а не 128.   -  person Peter Lawrey    schedule 15.12.2011


Ответы (2)


Вы сойдете с ума и потратите много времени, пытаясь выяснить конкретные случаи, когда это работает или не работает. Это зависит от реализации кода, который не всегда виден вам.

Суть: никогда, никогда не используйте == для сравнения Integer экземпляров, и точка. Как вы видели, иногда, при определенных обстоятельствах, это срабатывает, а в остальное время с треском проваливается. Если у вас есть метод, который возвращает целое число, присвойте значение int, а затем вы можете использовать == для сравнения этого int с другим int.

person Ernest Friedman-Hill    schedule 15.12.2011
comment
Мне очень жаль. Описание намерений не ясно. - person Argun; 15.12.2011
comment
Суть в том, что if(n.getConfirmStatus() == NoticeConfirmStatus.UNCONFIRMED.getValue()) и перейти в спящий режим, как установитьConfirmStatus(). Поскольку выражение возвращает false, я думаю, что методу установки нравится эта операция. . n.setConfirmStatus(new Integer(1)), а не n.setConfirmStatus(Integer.valueOf(1)). Но я не знал, как доказать свое утверждение. Вы понимаете мои смыслы? Спасибо! - person Argun; 15.12.2011
comment
Вы говорите, что думаете, что Hibernate не использует Integer.valueOf(). Я бы не обязательно ожидал этого. Он может иметь особые случаи для примитивных оболочек, а может и не иметь. Ваш эксперимент, кажется, показывает, что это не так; Я не нахожу это ужасно удивительным. - person Ernest Friedman-Hill; 15.12.2011

КОРОТКО: (ответы на вопрос)

Если вы хотите сравнить Integers как объекты, вы должны использовать .equals:

i.equals(j);
m.equals(n);

При этом они оба должны вернуть true. Но если вы действительно хотите использовать ==, вам нужно получить примитивное значение int:

i.intValue() == j.intValue();
m.intValue() == j.intValue();

ДЛИННОЕ: (объясняет ответ)

Основой этого является то, что Object всегда хранятся отдельно в памяти (за исключением некоторых особых случаев, таких как m=n), и для правильного сравнения их необходимо разбить на примитивные типы, которые можно успешно сравнивать с помощью ==.

Каждый Object имеет метод .equals(), унаследованный от Object как его суперкласс. Однако для корректного сравнения его необходимо переопределить. Integer переопределяет этот метод для успешного сравнения с Integer объектами, в то время как использование == проверяет, указывают ли оба объекта на одно и то же пространство в памяти, и поскольку два экземпляра Object не могут указывать на одно и то же пространство в памяти, это всегда будет возвращать false.

Однако, как указывает ваш код, есть некоторые особые случаи, которые работают, например:

  1. В вашем коде используется Integer i = 1, который считается "стандартным экземпляром" и может сравниваться с использованием ==.
  2. Если вы установите один Object равным другому, используя =, Java сообщит обоим объектам, чтобы они указывали на одно и то же место в памяти, что означает, что == вернет true.

Есть много других, но это два, которые приходят на ум и кажутся актуальными.

person Jon Egeland    schedule 15.12.2011
comment
Спасибо! Обзор знаний. Сравните содержимое переменной, используя equals(), сошлись, используя == - person Argun; 15.12.2011