Правильно ли для equals() зависеть только от идентификатора?
Предположим, что у меня есть класс User
:
public class User {
private Long id;
private String name;
private Integer age;
private BigDecimal account;
// other fields, getters and setters
}
Правильно ли переопределить метод equals
следующим образом?
@Override
public boolean equals(Object ob) {
if (ob == null) {
return false;
}
if (this == ob) {
return true;
}
if (ob instanceof User) {
User other = (User) ob;
return this.id.equals(other.getId());
}
return false;
}
Оказывается, что уникальность объекта определяется только его идентификатором. Но в моем приложении id
всегда уникален. Он предоставлен в базе данных. Является ли моя реализация equals
достаточно компетентной, чтобы учесть это? Или это не лучшая практика?
Конечно, я понимаю, что в этом случае реализация hashCode
должна быть следующей:
@Override
public int hashCode() {
return id.intValue();
}
Ответы
Ответ 1
Следует ли вам это делать, это зависит от семантики вашего класса. То есть, что означает сказать, что два объекта вашего класса эквивалентны? Самое важное отличие - это объекты с семантикой значений и объекты с семантикой сущности. Объекты Entity не эквивалентны, даже если они имеют эквивалентные атрибуты (цвет, длина и т.д.). Во многих случаях, в том числе, когда объект был прочитан из таблицы базы данных с первичным ключом, объекты объекта будут иметь уникальное поле идентификатора. Сравнение только поля идентификатора в этом случае - это правильная вещь.
Ответ 2
Это хорошо. До тех пор, пока у двух разных пользователей не будет одинакового идентификатора, ваша функция equals
будет достаточной. Может возникнуть проблема, если один пользователь может быть представлен дважды с другим ID (по любой причине), и вы хотите считать их равными.
Ответ 3
ваш метод equals() dosen't выглядит так, как будто он был сгенерирован IDE, поскольку он не проверяет значение "id" null, как указано в @Eric..
это то, что мой метод equals()/hashCode() выглядел так же, как и тот же идентификатор id
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User11 other = (User11) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
мы всегда должны использовать автоматическую генерацию для кода шаблона, где это возможно, так как оно намного меньше подвержено ошибкам.
также, в отношении вашей точки относительно уникальности "id" prop, которая зависит от ваших предпочтений и того, как вы хотите использовать вас, равна методу (бизнес-требование), т.е. если два имени пользователя одинаковы, они должны считаться одинаковыми при сравнении двух Пользовательские объекты позже..
Ответ 4
Хорошо использовать id для метода equals
, если вам не нужно сравнивать объект, который еще не был сохранен в БД. Если вы хотите сравнить объекты, которые еще не были сохранены, вам придется сравнить их атрибуты.
Ответ 5
Я согласен, что это на id.
Но у меня были проблемы с получением данных, которые должны обновлять базу данных.
В этом примере с User, где equals посмотрел только ID, я создал это.
interface DataEquals<T extends DataEquals> {
public boolean isDataEquals(T other)
}
User implements DataEquals<User> {
public boolean isDataEquals(User other) {
boolean b1 = getName().equals(other.getName());
boolean b2 = getAge().equals(other.getAge());
boolean b3 = getAccount().equals(other.getAccount());
return b1 && b2 && b3;
}
}
С этим мы можем иметь это.
public class ListChanges<T extends DataEquals<T>> {
private List<T> added = new ArrayList<T>();
private List<T> removed = new ArrayList<T>();
private List<T> changed = new ArrayList<T>();
private List<T> unchanged = new ArrayList<T>();
public ListChanges() {
super();
}
public List<T> getAdded() {
return added;
}
public List<T> getChanged() {
return changed;
}
public List<T> getRemoved() {
return removed;
}
public List<T> getUnchanged() {
return unchanged;
}
public boolean hasAnyChanges() {
return added.size()>0 || removed.size()>0 || changed.size()>0;
}
public void parse(List<T> oldList,List<T> newList) {
for (T oldObj : oldList) {
int index =newList.indexOf(oldObj);
if (index==-1) {
removed.add(oldObj);
} else {
T newObj = newList.get(index);
if (newObj.isDataEquals(oldObj)) {
unchanged.add(oldObj);
} else {
changed.add(newObj);
}
}
}
for (T newObj : newList) {
if (oldList.indexOf(newObj)==-1) {
added.add(newObj);
}
}
}
}
Тогда мы можем сделать это
List<User> oldList = ....;
List<User> newList = ...;
ListChanges<User> listChanges = new ListChanges<User>();
listChanges.parseChanges(oldList,newList);
Согласны ли вы, что это способ сделать это.??????