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
объектом? Казалось, единственное отличие состоит в том, что он был создан из одного и того же класса и заполнен только одним элементом данных. Я очень, очень смущен. Пожалуйста, пролить немного света?
источник
Ответы:
В Java
equals()
метод, который наследуется отObject
:Другими словами, параметр должен иметь тип
Object
. Это называется переопределением ; ваш методpublic boolean equals(Book other)
делает то , что называется перегрузкой кequals()
методу.В
ArrayList
использует переопределенныеequals()
методы для сравнения содержимого (например , для егоcontains()
иequals()
методов), не перегруженных из них. В большей части вашего кода вызывать тот, который не корректно переопределяетObject
equals, было хорошо, но не совместимо сArrayList
.Таким образом, неправильная переопределение метода может вызвать проблемы.
Я переопределить равняется следующему каждый раз:
Использование
@Override
аннотации может помочь тонне с глупыми ошибками.Используйте его всякий раз, когда вы думаете, что переопределяете метод суперкласса или интерфейса. Таким образом, если вы сделаете это неправильно, вы получите ошибку компиляции.
источник
if (!(other instanceof MyClass))return false;
возвращаетfalse
ifMyClass
расширяет другой класс. Но он не вернется,false
если другой класс расширитсяMyClass
. Не должноequal
быть менее противоречивым?Если вы используете Eclipse, просто перейдите в верхнее меню
источник
Немного не по теме, но, вероятно, стоит упомянуть:
У Commons Lang есть несколько превосходных методов, которые вы можете использовать в переопределении equals и hashcode. Проверьте EqualsBuilder.reflectionEquals (...) и HashCodeBuilder.reflectionHashCode (...) . В прошлом я избавил меня от головной боли - хотя, конечно, если вы просто хотите сделать «равные» по ID, это может не соответствовать вашим обстоятельствам.
Я также согласен с тем, что вам следует использовать
@Override
аннотацию всякий раз, когда вы переопределяете «равно» (или любой другой метод).источник
right click -> source -> generate hashCode() and equals()
,Другим быстрым решением, которое сохраняет стандартный код, является аннотация Lombok EqualsAndHashCode . Это легко, элегантно и настраиваемо. И не зависит от IDE . Например;
Посмотрите доступные опции, чтобы настроить, какие поля использовать в равных. Ломбок avalaible в мавена . Просто добавьте его с предоставленной областью:
источник
в Android Studio есть alt + insert ---> equals и hashCode
Пример:
источник
Рассматривать:
источник
obj
объявлен какObject
. Суть наследования в том , что вы можете назначитьBook
дляobj
. После этого, если вы не предполагаете, что anObject
не должен быть сопоставим сString
viaequals()
, этот код должен быть абсолютно легальным и возвращатьсяfalse
.instanceOf
утверждение часто используется при реализации равных.Это популярная ловушка!
Проблема в том, что использование
instanceOf
нарушает правило симметрии:(object1.equals(object2) == true)
если и только если(object2.equals(object1))
если первое равенство равно true, а object2 является экземпляром подкласса класса, к которому принадлежит obj1, то второе равенство вернет false!
если рассматриваемый класс, к которому принадлежит ob1, объявлен как final, то эта проблема не может возникнуть, но в целом вы должны проверить следующее:
this.getClass() != otherObject.getClass();
если нет, верните false, в противном случае проверьте поля для сравнения на равенство!источник
equals()
метода. Он рекомендует против использованияgetClass()
. Основная причина в том, что это нарушает принцип подстановки Лискова для подклассов, которые не влияют на равенство.recordId является свойством объекта
источник