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


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

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

во всяком случае -

я разрабатывал основную корзину покупок который может содержать 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 объектов и заполнить их данными. У многих добавляет, удаляет, имеет() операции на 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   143   2008-10-09 08:22:57

8 ответов:

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

public boolean equals(Object other);

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

The 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() and 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...

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