Переопределение метода java equals () - не работает?

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

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

абы -

я разрабатывал базовую корзину который может содержать ArrayList of 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 объект только the ID в нем из книги класс. Никакие другие данные в него не вводились. В основном следующее:

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 класс был правильно протестирован и правильный. После swaapping в equals() метод следующим образом:

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

все снова начало работать. Есть ли причина, по которой метод решил не принимать параметр книги, хотя он явно был a

8 ответов


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

public boolean equals(Object other);

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

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

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

Я переопределяю равняется следующему каждый раз:

@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, просто перейдите в верхнее меню

Source --> Generate equals () и hashCode ()


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

Commons Lang имеет некоторые отличные методы, которые вы можете использовать для переопределения equals и hashcode. Проверьте EqualsBuilder.reflectionEquals(...) и HashCodeBuilder.reflectionHashCode(...). Спас меня много головной боли в прошлом, хотя, конечно, если вы просто хотите сделать "равными" по ID, он может не соответствовать вашим условиям.

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


другое быстрое решение, которое сохраняет шаблонный код, -Ломбок 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, тогда второй equals вернет false!

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

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