Правильно ли для 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);

Согласны ли вы, что это способ сделать это.??????