Переопределить метод равных - PullRequest
3 голосов
/ 16 июня 2011

вопрос новичка здесь:

Так что в моей домашней работе в университете я должен переопределить метод равных классов объекта для нового созданного мной класса.

Новый класс - «Продукт», каждыйУ продукта есть атрибут "id", который является уникальным.Вот как я это переопределил:

@Override
public boolean equals(Object obj) {
       final Product other = (Product) obj;
       if (id != other.id)
           return false;
       return true;
   }

Дело в том, что это составляет 1,5 балла из 10, и это заставило меня подозревать, что это так просто.Итак, я начал поиск и нашел такие вещи, как:

@Override
public boolean equals(Object obj) {
       if (this == obj)
           return true;
       if (obj == null)
           return false;
       if (getClass() != obj.getClass())
           return false;
       final Product other = (Product) obj;
       if (id != other.id)
           return false;
       return true;
   }

, которые вообще не имеют смысла для меня, потому что я думаю, что последний if проверяет все остальные ограничения ifs.Как вы думаете, ребята? Какой лучший способ переопределить этот метод?

Спасибо!

Ответы [ 5 ]

14 голосов
/ 16 июня 2011

Второй кусок кода лучше:

  • Оптимизирует для x.equals(x), что не является необходимым для корректности, но является полезной оптимизацией
  • Он справляется с x.equals(null) вместо броска NullPointerException
  • Он обрабатывает объекты совершенно другого класса, не выбрасывая ClassCastException, который ваш (например, x.equals("foo"))
  • Требуется точный того же типа для обеспечения симметричных отношений; в противном случае obj.equals(x) может вызвать другой метод, давая другой результат.
2 голосов
/ 16 июня 2011

Вторая версия безопасна, я бы сказал, педантичная.Вместо этого ваша версия может запустить ClassCastException, поскольку вы предполагаете, что тип времени выполнения переменной obj имеет тип product.Это неправда, поэтому вы должны использовать this.getClass() != obj.getClass() (вы можете решить эту проблему также с помощью оператора instanceof).

Если я сделаю

Product p = new Product();
p.equals("abc");

, я получаю исключение, покаЯ должен получить false.

Кроме того, он управляет проблемой product.equals(null), которая должна возвращать false, как указано в методе контракта equals в документации.Если вас это не волнует, и вам это нравится, то внутри вас равно:

...
Product p = (Product)obj; // obj is null
obj.id // this throws a NullPointerException
1 голос
/ 16 июня 2011

Общая идиома, используемая в переопределении equals ():

@Override
public boolean equals(Object obj) {
       if (! (obj instanceof Product) ) return false;

       final Product other = (Product) obj;
       if (id != other.id)
           return false;
       return true;
   }

Во второй опубликованной вами версии:

  • первый if () может быть хорош для оптимизация только если следующее чеки слишком дороги. Но это не так, так что это просто избыточный код, который является злом.
  • Эта версия не будет работать, если вы определите подкласс Product, который не меняет семантику метода equals (). (Например, класс, который обеспечивает некоторый удобный метод, но нет дополнительного внутреннего состояния к объекты.) Это из-за третий если ().
0 голосов
/ 16 июня 2011

Решение, предложенное «Джошуа Блох: Эффективная Java», таково (при условии, что Product не имеет суперкласса, отличного от Object):

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof Product)) return false;
    final Product other = (Product) obj;
    if (id != other.id) return false;
    return true;
}

Ваше первое решение имеет два недостатка:

  • new Product(1).equals(null) выдает исключение NullpointerException, хотя в Object.equals () указано, что оно возвращает false.
  • new Product(1).equals(new Vector()) выдает исключение ClassCastException, хотя в Object указывается, что оно возвращает false.equals ().

Оба они исправляются проверкой экземпляра.if (this == obj) return true; часто полезен для эффективности, но, возможно, здесь и не нужен.

Второе опубликованное вами решение затрудняет написание подкласса Product с хорошей семантикой.Если у вас есть подкласс

public class SubProduct extends Product {
    SubProduct(int id) {
         super(id);
    }
    ...
}

, у вас будет !new Product(4).equals(new SubProduct(4)).Это нарушает принцип подстановки Лискова и часто считается не очень хорошим.Если у вас есть последний класс, вторые решения такие же, как указано выше.

0 голосов
/ 16 июня 2011

Номер 2 прямо из Эффективной Java для наиболее безопасного способа переопределения равных. 1 имеет нулевой указатель, если объект равен нулю, и он не так оптимизирован, как мог бы (не проверяет, является ли ojb ссылкой на себя)

...