Переопределите Superclass Equals и HashCode и подумайте, что я должен сделать то же самое с подклассом - PullRequest
2 голосов
/ 15 декабря 2011

У меня есть суперкласс с 2 переменными (int a) (int b), и у меня есть подкласс, который расширяет функциональные возможности суперкласса путем переопределения 2 методов суперкласса с улучшенными методами, которые теперь находятся в подклассе. Как часть моего подкласса у меня теперь есть новый int (int c), который является уникальным идентификатором (UUID).

Я понимаю, что равенство трудно поддерживать методом equals

Могу ли я переопределить методы equals и hashCode суперкласса, чтобы показать равенство И также сделать то же самое для методов equals и hashCode подкласса, основываясь на моей ситуации, описанной выше?

Я изначально переопределил методы equals и hashCode в суперклассе. Если это предполагается сделать для подкласса также из-за дополнительной переменной экземпляра (int c) в подклассе. Я понимаю, что должен быть метод hashCode, чтобы показать это, и я читаю, если haschCode изменяется, то метод equals подкласса должен измениться?

Я действительно запутался в том, что лучше делать.

Мне было интересно, могут ли мои методы суперкласса equals и hashCode показать отношения равенства? Разрешено ли в сочетании с моими переопределенными методами equals и hashCode суперкласса, что подкласс может показывать сравнение для int a, int b и int c и hashCode методов подкласса, обновленных, чтобы показать уникальный хэш-код для int s a, b и c?

Я думал сравнить мои int s a и b в методе суперкласса equals и обновить хеш-код для этих 2 переменных и int s a, b и c в методе equals обновите хеш-код для этих трех переменных. Просто int c в суперклассе уникален?

Очень благодарен за любые советы, поскольку я считаю, что игнорировать и не иметь дело с int c в подклассе equals и hashCode методами может быть нет.

Заранее спасибо

Ответы [ 5 ]

1 голос
/ 15 декабря 2011

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

Если это так, не переопределяйте equals()и hashCode() методы.Вы можете даже сделать их final в суперклассе.

Если нет, то метод equals() каждого класса должен проверять тип аргумента на equals(), используя getClass(), а не instanceof,Например, в суперклассе:

if ((obj == null) || (!getClass().equals(obj.getClass()))
  return false;
/* Compare a and b. */
...

В подклассе:

if (!super.equals(obj))
  return false;
/* Compare c. */
...

Если хеш-код основан на полях a и b, вы, вероятно, выиграли 'У есть для переопределения метода hashCode(), но ваш класс, вероятно, будет работать лучше в качестве ключа, если вы учитываете c в реализации подкласса.Таким образом, он будет помещать ключи с разными значениями c в разные сегменты, а не объединять все экземпляры с одинаковыми a и b в одном и том же блоке хеш-функции.

1 голос
/ 15 декабря 2011

В принципе, у вас есть два возможных варианта:

  1. Игнорировать c в целом.Определите равенство для суперкласса в терминах a и b и не переопределяйте его в подклассах.

  2. Всегда обрабатывайте экземпляры суперкласса и подкласса как не равные.Он позволяет по-разному определять равенство в суперклассе (на основе a и b) и подклассе (на основе a, b и c).

    Обратите внимание, что переопределение equals()и hashcode в подклассе недостаточно в этом случае - вам также понадобится специальный прием при реализации метода equals() суперкласса, см. часть о canEquals() методе в Как написать метод равенства в Java .

0 голосов
/ 15 декабря 2011

Чтобы определить поведение hashCode и equals, необходимо рассмотреть несколько сценариев.

class Foo { int a, b; }
class Bar extends Foo { int c;}

Равны ли значения Foo и Bar с одинаковыми значениями a и b (т. Е. Представляют ли они одно и то же значение)? Если так, то добавьте реализацию equals и hashCode в Foo и не переопределяйте ее в Bar. В случае равенства убедитесь, что объект является instanceOf Foo, а не равенством классов.

Равны ли экземпляры Bar с разными c? Если так, то не переопределяйте реализацию Foo hashCode и равно.

В противном случае у вас должна быть реализация equals и hashCode как в Foo, так и в Bar. Убедитесь, что все элементы Foo равны другим экземплярам Foo, а экземпляры Bar равны только другим экземплярам Bar. Если нет, вы можете легко нарушить симметрию, требуемую равенством, например,

Foo x = new Foo(a,b);
Bar y = new Bar(a,b,c);
x.equals(y); //returns false
y.equals(x); //returns true

Вышеуказанное очень плохо и приведет к странному поведению, если, например, вы положили Foo и Bar в сет.

Наконец, вы НЕ должны писать свою собственную реализацию hashCode и equals для этих объектов. У большинства IDE есть инструмент для автоматической генерации, используйте его вместо этого.

0 голосов
/ 15 декабря 2011

Это зависит. Допустим, ваш суперкласс A и B extends A, тогда это может произойти

  • a.equals(a)
  • b.equals(b)
  • a.equals(b) (правда)? b.hash == a.hash: хэш не имеет значения
  • b.equals(a) (правда)? b.hash == a.hash: хэш не имеет значения

Как должны быть связаны A и B? Есть два варианта:

  1. A и B совершенно разные, поэтому a.equals(b) или b.equals(a) равны всегда ложно . Это самый безопасный способ . Вам нужно в равенстве проверить a.getClass() == b.getClass();, чтобы убедиться, что a и b равны точно такого же типа . Например, Eclipse IDE автоматически генерирует такой вид равенства по умолчанию в generate equals () и hashCode ().
  2. A и B можно сравнить, но вы не можете переопределить его в B, чтобы сохранить контракт equals() и hashCode(). Это принудительно из-за симметричного контракта (a.equals(b) == b.equals(a)) равных.
0 голосов
/ 15 декабря 2011

++ - Джордан Бентли.

Как правило, рекомендуется переопределять equals(), toString() и hashCode() для каждого класса, который вы пишете.На практике это не всегда имеет смысл.Но за то, что ты делаешь, я бы так и сделал.И да, вы можете изменить реализацию в подклассе.

Хорошо пометить каждый из ваших переопределенных методов с помощью @Override, чтобы помочь предоставить документацию разработчикам, которых вы переопределяете.Это подсказывает им, что вы по крайней мере переопределяете java.lang.Object, если не ваш суперкласс.

...