Переопределение метода javaquals() – не работает?

StackOverflow https://stackoverflow.com/questions/185937

  •  06-07-2019
  •  | 
  •  

Вопрос

Я столкнулся с интересной (и очень неприятной) проблемой с equals() Сегодняшний метод привел к сбою того, что я считал хорошо протестированным классом, и возникновению ошибки, на поиск которой мне потребовалось очень много времени.

Для полноты картины я не использовал IDE или отладчик — только старый добрый текстовый редактор и System.out.Время было очень ограничено, и это был школьный проект.

В любом случае -

Я разрабатывал базовую корзину для покупок, которая могла бы содержать ArrayList из Book объекты.Для того, чтобы реализовать addBook(), removeBook(), и hasBook() методы Корзины, я хотел проверить, Book уже существовал в Cart.Итак, я ухожу -

public boolean equals(Book b) {
    ... // More code here - null checks
    if (b.getID() == this.getID()) return true;
    else return false;
}

В тестировании все работает нормально.Я создаю 6 объектов и заполняю их данными.Выполняйте множество операций добавления, удаления, has() в Cart и все работает нормально.Я читал, что ты можешь либо иметь equals(TYPE var) или equals(Object o) { (CAST) var } но предположил, что, поскольку это работает, это не имеет большого значения.

Потом я столкнулся с проблемой - мне нужно было создать Book объект с только тот ID в нем из класса Book.Никакие другие данные в него вноситься не будут.В основном следующее:

public boolean hasBook(int i) {
    Book b = new Book(i);
    return hasBook(b);
}

public boolean hasBook(Book b) {
    // .. more code here
    return this.books.contains(b);
}

Внезапно, equals(Book b) метод больше не работает.Это заняло ОЧЕНЬ много времени, без хорошего отладчика и при условии, что Cart класс был должным образом протестирован и корректен.После замены equals() метод следующим образом:

public boolean equals(Object o) {
    Book b = (Book) o;
    ... // The rest goes here   
}

Все снова начало работать.Есть ли причина, по которой метод решил не принимать параметр Book, хотя он явно был а Book объект?Единственная разница заключалась в том, что он был создан из того же класса и заполнен только одним элементом данных.Я очень-очень смущен.Пожалуйста, пролейте свет?

Это было полезно?

Решение

В Java метод equals () , унаследованный от Object , имеет вид:

public boolean equals(Object other);

Другими словами, параметр должен иметь тип Object .

ArrayList использует правильный метод equals, где вы всегда вызывали тот, который не корректно переопределял equals Object .

Неправильная переопределение метода может вызвать проблемы.

Я переопределяю, равняется следующему:

@Override
public boolean equals(Object other){
    if (other == null) return false;
    if (other == this) return true;
    if (!(other instanceof MyClass))return false;
    MyClass otherMyClass = (MyClass)other;
    ...test other properties here...
}

Использование аннотации @Override может помочь с глупыми ошибками.

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

Другие советы

Если вы используете Eclipse, просто перейдите в верхнее меню

  

Источник - > Создать равно () и   хэш-код ()

Немного не по теме, но, вероятно, стоит упомянуть в любом случае:

Commons Lang предлагает несколько превосходных методов, которые можно использовать для переопределения равенства и хэш-кода. Проверьте EqualsBuilder.reflectionEquals (...) и HashCodeBuilder.reflectionHashCode (...) . Это избавило меня от головной боли в прошлом - хотя, конечно, если вы просто хотите сделать «равно» на удостоверение личности это может не соответствовать вашим обстоятельствам.

Я также согласен с тем, что вы должны использовать аннотацию @Override всякий раз, когда вы переопределяете equals (или любой другой метод).

Еще одним быстрым решением, которое сохраняет стандартный код, является аннотация Lombok EqualsAndHashCode . Это легко, элегантно и настраиваемо. И не зависит от IDE . Например;

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(of={"errorNumber","messageCode"}) // Will only use this fields to generate equals.
public class ErrorMessage{

    private long        errorNumber;
    private int         numberOfParameters;
    private Level       loggingLevel;
    private String      messageCode;

См. параметры , чтобы указать, какие поля использовать в равных. Ломбок доступен в maven . Просто добавьте его с предоставленной областью действия:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.14.8</version>
    <scope>provided</scope>
</dependency>

В Android Studio есть alt + INSERT ---> equals и Hashcode

Пример:

    @Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Proveedor proveedor = (Proveedor) o;

    return getId() == proveedor.getId();

}

@Override
public int hashCode() {
    return getId();
}

Учитывать:

Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...

оператор instanceOf часто используется в реализации equals.

Это популярная ловушка!

Проблема в том, что использование instanceOf нарушает правило симметрии:

(object1.equals (object2) == true) тогда и только тогда, когда (object2.equals (object1))

если первое значение равно true, а object2 является экземпляром подкласса класс, к которому принадлежит obj1, тогда второе равенство вернет false!

если рассматриваемый класс, к которому принадлежит ob1, объявлен как final, то этот Проблема не может возникнуть, но в целом вы должны проверить следующее:

this.getClass ()! = otherObject.getClass (); , если нет, вернуть false, в противном случае проверить поля для сравнения на равенство!

recordId является свойством объекта

@Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Nai_record other = (Nai_record) obj;
        if (recordId == null) {
            if (other.recordId != null)
                return false;
        } else if (!recordId.equals(other.recordId))
            return false;
        return true;
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top