Лучшая реализация? Это сложный вопрос, потому что это зависит от модели использования.
Практически во всех случаях разумная хорошая реализация была предложена в « Эффективной Java» Джоша Блоха в статье 8 (второе издание). Лучше всего искать это там, потому что автор объясняет, почему подход хорош.
Короткая версия
Создайте int resultи назначьте ненулевое значение.
Для каждого поля,f проверенного в equals()методе, рассчитайте хеш-код c:
Если поле f является boolean: вычислить (f ? 0 : 1);
Если поле F является byte, char, shortили int: вычислить (int)f;
Если поле f является long: вычислить (int)(f ^ (f >>> 32));
Если поле f является float: вычислить Float.floatToIntBits(f);
Если поле f является double: вычислить Double.doubleToLongBits(f)и обработать возвращаемое значение, как любое длинное значение;
Если поле f является объектом : используйте результат hashCode()метода или 0 if f == null;
Если поле f является массивом : рассмотрите каждое поле как отдельный элемент и вычислите значение хеш-функции рекурсивным способом и объедините значения, как описано далее.
Объедините значение хеша cс result:
result =37* result + c
Возвращение result
Это должно привести к правильному распределению значений хеш-функции для большинства ситуаций использования.
Да, мне особенно любопытно, откуда происходит число 37.
Кип
17
Я использовал пункт 8 книги Джоша Блоха «Эффективная Ява».
дмейстер
39
@dma_k Причина использования простых чисел и метода, описанного в этом ответе, заключается в том, чтобы гарантировать, что вычисленный хэш-код будет уникальным . При использовании не простых чисел вы не можете гарантировать это. Неважно, какое простое число вы выберете, в числе 37 нет ничего волшебного (жаль, что 42 не простое число, а?)
Симон Форсберг,
34
@ SimonAndréForsberg Ну, вычисляемый хеш-код не всегда может быть уникальным :) Это хеш-код. Однако у меня возникла идея: простое число имеет только один множитель, в то время как не простое имеет как минимум два. Это создает дополнительную комбинацию для оператора умножения, чтобы привести к тому же хешу, то есть вызвать столкновение.
Если у кого-то нет веских причин не использовать их, то в любом случае следует обязательно их использовать. (Формулировка более сильная, как это ИМХО должна быть сформулирована.) Применяются типичные аргументы для использования стандартных реализаций / библиотек (лучшие практики, хорошо протестированные, менее подверженные ошибкам и т. Д.).
Киссаки
7
@ justin.hughey ты, кажется, запутался. Единственный случай, который вы должны переопределить, hashCode- это если у вас есть пользовательский интерфейс equals, и именно для этого и предназначены эти библиотечные методы. В документации совершенно ясно об их поведении по отношению к equals. Реализация библиотеки не претендует на то, чтобы освободить вас от знания характеристик правильной hashCodeреализации - эти библиотеки упрощают реализацию такой соответствующей реализации в большинстве случаев, где equalsона переопределяется.
Бакар
6
Для всех разработчиков Android, которые смотрят на класс java.util.Objects, он был представлен только в API 19, поэтому убедитесь, что вы работаете на KitKat или выше, в противном случае вы получите NoClassDefFoundError.
Эндрю Келли
3
Лучший ответ IMO, хотя в качестве примера я бы предпочел выбрать java.util.Objects.hash(...)метод JDK7, чем метод guava com.google.common.base.Objects.hashCode(...). Я думаю, что большинство людей предпочли бы стандартную библиотеку за дополнительную зависимость.
Malte Skoruppa
2
Если есть два или более аргументов и если какой-либо из них является массивом, результат может быть не таким, как вы ожидаете, потому что hashCode()для массива это просто его java.lang.System.identityHashCode(...).
Старикофф
59
Лучше использовать функциональность, предоставляемую Eclipse, которая довольно неплохо работает, и вы можете приложить свои усилия и энергию для разработки бизнес-логики.
+1 Хорошее практическое решение. Решение dmeister более всеобъемлющее, но я склонен забывать обрабатывать пустые значения, когда пытаюсь написать хеш-коды самостоятельно.
Quantum7
1
+1 Согласен с Quantum7, но я бы сказал, что очень хорошо понимать, что делает реализация, сгенерированная Eclipse, и откуда она получает подробности своей реализации.
jwir3
15
Извините, но ответы, включающие «функциональность, предоставляемую [некоторыми IDE]», не очень актуальны в контексте языка программирования в целом. Существуют десятки IDE, и это не отвечает на вопрос ... а именно потому, что это больше касается алгоритмического определения и напрямую связано с реализацией equals () - о чем IDE ничего не будет знать.
@Overridepublicint hashCode(){// Start with a non-zero constant. Prime is preferredint result =17;// Include a hash for each field.// Primatives
result =31* result +(booleanField ?1:0);// 1 bit » 32-bit
result =31* result + byteField;// 8 bits » 32-bit
result =31* result + charField;// 16 bits » 32-bit
result =31* result + shortField;// 16 bits » 32-bit
result =31* result + intField;// 32 bits » 32-bit
result =31* result +(int)(longField ^(longField >>>32));// 64 bits » 32-bit
result =31* result +Float.floatToIntBits(floatField);// 32 bits » 32-bitlong doubleFieldBits =Double.doubleToLongBits(doubleField);// 64 bits (double) » 64-bit (long) » 32-bit (int)
result =31* result +(int)(doubleFieldBits ^(doubleFieldBits >>>32));// Objects
result =31* result +Arrays.hashCode(arrayField);// var bits » 32-bit
result =31* result + referenceField.hashCode();// var bits » 32-bit (non-nullable)
result =31* result +// var bits » 32-bit (nullable) (nullableReferenceField ==null?0: nullableReferenceField.hashCode());return result;}
РЕДАКТИРОВАТЬ
Как правило, когда вы переопределяете hashcode(...), вы также хотите переопределить equals(...). Так что для тех, кто будет или уже реализован equals, вот хорошая ссылка от моего Github ...
@Overridepublicboolean equals(Object o){// Optimization (not required).if(this== o){returntrue;}// Return false if the other object has the wrong type, interface, or is null.if(!(o instanceofMyType)){returnfalse;}MyType lhs =(MyType) o;// lhs means "left hand side"// Primitive fieldsreturn booleanField == lhs.booleanField
&& byteField == lhs.byteField
&& charField == lhs.charField
&& shortField == lhs.shortField
&& intField == lhs.intField
&& longField == lhs.longField
&& floatField == lhs.floatField
&& doubleField == lhs.doubleField
// Arrays&&Arrays.equals(arrayField, lhs.arrayField)// Objects&& referenceField.equals(lhs.referenceField)&&(nullableReferenceField ==null? lhs.nullableReferenceField ==null: nullableReferenceField.equals(lhs.nullableReferenceField));}
если equals () возвращает true для двух объектов, то hashCode () должна возвращать одно и то же значение. Если equals () возвращает false, то hashCode () должен возвращать разные значения
Я не могу с тобой согласиться. Если два объекта имеют одинаковый хеш-код, это не означает, что они равны.
Если A равно B, то A.hashcode должен быть равен B.hascode
но
если A.hashcode равен B.hascode, это не означает, что A должен быть равен B
Если это (A != B) and (A.hashcode() == B.hashcode())то, что мы называем коллизией хеш-функции. Это потому, что кодомен хеш-функции всегда конечен, а домен - нет. Чем больше кодомен, тем реже должно происходить столкновение. Хорошие хеш-функции должны возвращать разные хеш-функции для разных объектов с максимально возможной вероятностью, учитывая конкретный размер кодомена. Это редко может быть полностью гарантировано, хотя.
Кшиштоф Яблоньский
Это должен быть просто комментарий к вышеупомянутому посту Грею. Хорошая информация, но она на самом деле не отвечает на вопрос
Кристофер Ручински
Хорошие комментарии, но будьте осторожны с использованием термина «разные объекты» ... потому что equals () и, следовательно, реализация hashCode () не обязательно относятся к разным объектам в контексте ОО, но обычно больше относятся к их представлениям модели предметной области (например, два люди могут считаться одинаковыми, если они совместно используют код страны и идентификатор страны - хотя это могут быть два разных «объекта» в JVM - они считаются «равными» и имеют заданный хэш-код) ...
Даррелл Тиг,
7
Если вы используете eclipse, вы можете сгенерировать equals()и hashCode()использовать:
Source -> Generate hashCode () и equals ().
Используя эту функцию, вы можете решить, какие поля вы хотите использовать для вычисления равенства и хеш-кода, и Eclipse генерирует соответствующие методы.
Недостатком этого API является то, что вы платите стоимость создания объекта каждый раз, когда вызываете метод equals и hashcode (если только ваш объект не является неизменяемым и вы предварительно вычисляете хеш), что может быть много в некоторых случаях.
Джеймс МакМэхон
до недавнего времени это был мой любимый подход. Я столкнулся с StackOverFlowError при использовании критериев для ассоциации SharedKey OneToOne. Более того, Objectsкласс предоставляет hash(Object ..args)& equals()методы из Java7 на. Они рекомендуются для любых приложений, использующих jdk 1.7+
Diablo
@Diablo Полагаю, вашей проблемой был цикл в графе объектов, и вам не повезло с большинством реализаций, так как вам нужно игнорировать какую-то ссылку или разорвать цикл (мандатировать IdentityHashMap). FWIW Я использую хэш-код на основе идентификатора и равняется для всех сущностей.
Maaartinus
6
Просто быстрое примечание для завершения другого более подробного ответа (в терминах кода):
Если я правильно понимаю ваш вопрос, у вас есть собственный класс коллекции (т. Е. Новый класс, который выходит из интерфейса Collection), и вы хотите реализовать метод hashCode ().
Если ваш класс коллекции расширяет AbstractList, вам не нужно об этом беспокоиться, уже есть реализация equals () и hashCode (), которая работает путем перебора всех объектов и добавления их hashCodes () вместе.
Теперь, если то, что вы хотите, является наилучшим способом вычисления хеш-кода для определенного класса, я обычно использую оператор ^ (побитовый исключающий или) для обработки всех полей, которые я использую в методе equals:
(Вы можете получить hashCode непосредственно из int в Java в эти дни? Я думаю, что это делает автокастинг ... если это так, пропустите toString, это уродливо.)
ошибка в длинном ответе about8.blogspot.com - получение хеш-кода из конкатенации строк оставляет вас с хеш-функцией, одинаковой для любой комбинации строк, которые складываются в одну и ту же строку.
SquareCog
1
Так что это мета-обсуждение и вообще не имеет отношения к вопросу? ;-)
Huppie
1
Это исправление предложенного ответа, которое имеет довольно существенный недостаток.
SquareCog
Это очень ограниченная реализация
Кристофер Ручински
Ваша реализация избегает проблемы и вводит другую; Обмен fooи barприводит к тому же hashCode. Ваш toStringAFAIK не компилируется, и если он это делает, то он ужасно неэффективен. Нечто подобное 109 * getFoo().hashCode() + 57 * getBar().hashCode()быстрее, проще и не вызывает ненужных столкновений.
Maaartinus
2
Поскольку вы специально спрашивали о коллекциях, я хотел бы добавить аспект, о котором другие ответы еще не упомянули: HashMap не ожидает, что их ключи изменят свой хэш-код после добавления в коллекцию. Победил бы всю цель ...
Если вы собираетесь использовать это, имейте в виду, что отражение стоит дорого. Честно говоря, я бы не стал использовать это ни для чего, кроме как выбрасывать код.
Джеймс МакМэхон
2
Я использую крошечную оболочку, Arrays.deepHashCode(...)потому что она правильно обрабатывает массивы, предоставленные в качестве параметров
Я предпочитаю использовать служебные методы из библиотеки Google Collections lib из класса Objects, которые помогают мне поддерживать мой код в чистоте. Очень часто equalsи hashcodeметоды делаются из шаблона IDE, поэтому они не чисты для чтения.
Вот еще одна демонстрация подхода JDK 1.7+ с учетом логики суперкласса. Я считаю это довольно удобным с учетом класса Object hashCode (), чистой зависимости JDK и без дополнительной ручной работы. пожалуйста, обратите вниманиеObjects.hash() что допускается нулевое значение.
Я не включил никакой equals()реализации, но в действительности это вам, конечно, понадобится.
import java.util.Objects;publicclassDemo{publicstaticclass A {privatefinalString param1;public A(finalString param1){this.param1 = param1;}@Overridepublicint hashCode(){returnObjects.hash(super.hashCode(),this.param1);}}publicstaticclass B extends A {privatefinalString param2;privatefinalString param3;public B(finalString param1,finalString param2,finalString param3){super(param1);this.param2 = param2;this.param3 = param3;}@Overridepublicfinalint hashCode(){returnObjects.hash(super.hashCode(),this.param2,this.param3);}}publicstaticvoid main(String[] args){
A a =new A("A");
B b =new B("A","B","C");System.out.println("A: "+ a.hashCode());System.out.println("B: "+ b.hashCode());}}
имеют то же значение hashCode, 31*(a+b) + cчто и множитель, используемый дляList.hashCode получает здесь повторно. Очевидно, что столкновения неизбежны, но создание ненужных столкновений просто ... ненужно.
Там нет ничего существенно умного в использовании 31. Множитель должен быть нечетным, чтобы избежать потери информации (любой четный множитель теряет по меньшей мере самый старший бит, кратные четыре теряют два и т. Д.). Любой нечетный множитель можно использовать. Маленькие множители могут привести к более быстрым вычислениям (JIT может использовать сдвиги и дополнения), но, учитывая, что умножение имеет задержку в три цикла на современных Intel / AMD, это вряд ли имеет значение. Маленькие множители также приводят к большему столкновению для небольших входов, что иногда может быть проблемой.
Использовать простое число бессмысленно, поскольку простые числа не имеют смысла в кольце Z / (2 ** 32).
Поэтому я бы рекомендовал использовать случайно выбранное большое нечетное число (не стесняйтесь брать простое число). Поскольку процессоры i86 / amd64 могут использовать более короткую инструкцию для подстановки операндов в один байт со знаком, то для множителей, подобных 109, есть небольшое преимущество в скорости. Для минимизации коллизий возьмите что-то вроде 0x58a54cf5.
Использование разных множителей в разных местах полезно, но, вероятно, недостаточно для оправдания дополнительной работы.
При объединении хеш-значений я обычно использую метод объединения, который используется в библиотеке boost c ++, а именно:
seed ^= hasher(v)+0x9e3779b9+(seed<<6)+(seed>>2);
Это делает довольно хорошую работу по обеспечению равномерного распределения. Для некоторого обсуждения того, как работает эта формула, смотрите сообщение StackOverflow: Магическое число в boost :: hash_combine
Наиболее важным является сохранение согласованности между hashCode () и equals (): если equals () возвращает true для двух объектов, то hashCode () должна возвращать одно и то же значение. Если equals () возвращает false, то hashCode () должен возвращать разные значения.
Вроде SquareCog уже заметили. Если хэш - код генерируется один раз из конкатенации двух строк чрезвычайно легко генерировать массу столкновений: ("abc"+""=="ab"+"c"=="a"+"bc"==""+"abc"). Это серьезный недостаток. Было бы лучше оценить хеш-код для обоих полей, а затем рассчитать их линейную комбинацию (предпочтительно с использованием простых чисел в качестве коэффициентов).
Кшиштоф Яблонский
@ KrzysztofJabłoński Право. Кроме того, обмен fooи barпроизводит ненужные столкновения тоже.
Objects.hashCode(collection)
должно быть идеальным решением!collection.hashCode()
( hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/... )Ответы:
Лучшая реализация? Это сложный вопрос, потому что это зависит от модели использования.
Практически во всех случаях разумная хорошая реализация была предложена в « Эффективной Java» Джоша Блоха в статье 8 (второе издание). Лучше всего искать это там, потому что автор объясняет, почему подход хорош.
Короткая версия
Создайте
int result
и назначьте ненулевое значение.Для каждого поля,
f
проверенного вequals()
методе, рассчитайте хеш-кодc
:boolean
: вычислить(f ? 0 : 1)
;byte
,char
,short
илиint
: вычислить(int)f
;long
: вычислить(int)(f ^ (f >>> 32))
;float
: вычислитьFloat.floatToIntBits(f)
;double
: вычислитьDouble.doubleToLongBits(f)
и обработать возвращаемое значение, как любое длинное значение;hashCode()
метода или 0 iff == null
;Объедините значение хеша
c
сresult
:Возвращение
result
Это должно привести к правильному распределению значений хеш-функции для большинства ситуаций использования.
источник
Если вы довольны реализацией Effective Java, рекомендованной dmeister, вы можете использовать библиотечный вызов вместо собственного:
Это требует либо Guava (
com.google.common.base.Objects.hashCode
) или стандартной библиотеки в Java 7 (java.util.Objects.hash
), но работает так же.источник
hashCode
- это если у вас есть пользовательский интерфейсequals
, и именно для этого и предназначены эти библиотечные методы. В документации совершенно ясно об их поведении по отношению кequals
. Реализация библиотеки не претендует на то, чтобы освободить вас от знания характеристик правильнойhashCode
реализации - эти библиотеки упрощают реализацию такой соответствующей реализации в большинстве случаев, гдеequals
она переопределяется.java.util.Objects.hash(...)
метод JDK7, чем метод guavacom.google.common.base.Objects.hashCode(...)
. Я думаю, что большинство людей предпочли бы стандартную библиотеку за дополнительную зависимость.hashCode()
для массива это просто егоjava.lang.System.identityHashCode(...)
.Лучше использовать функциональность, предоставляемую Eclipse, которая довольно неплохо работает, и вы можете приложить свои усилия и энергию для разработки бизнес-логики.
источник
Хотя это связано с
Android
документацией (Wayback Machine) и моим собственным кодом на Github , в целом это будет работать для Java. Мой ответ - это расширение ответа dmeister с помощью простого кода, который намного легче читать и понимать.РЕДАКТИРОВАТЬ
Как правило, когда вы переопределяете
hashcode(...)
, вы также хотите переопределитьequals(...)
. Так что для тех, кто будет или уже реализованequals
, вот хорошая ссылка от моего Github ...источник
Сначала убедитесь, что equals реализован правильно. Из статьи IBM DeveloperWorks :
Затем убедитесь, что их отношение с hashCode соответствует контакту (из той же статьи):
Наконец, хорошая хеш-функция должна стремиться приблизиться к идеальной хеш-функции .
источник
about8.blogspot.com, вы сказали
Я не могу с тобой согласиться. Если два объекта имеют одинаковый хеш-код, это не означает, что они равны.
Если A равно B, то A.hashcode должен быть равен B.hascode
но
если A.hashcode равен B.hascode, это не означает, что A должен быть равен B
источник
(A != B) and (A.hashcode() == B.hashcode())
то, что мы называем коллизией хеш-функции. Это потому, что кодомен хеш-функции всегда конечен, а домен - нет. Чем больше кодомен, тем реже должно происходить столкновение. Хорошие хеш-функции должны возвращать разные хеш-функции для разных объектов с максимально возможной вероятностью, учитывая конкретный размер кодомена. Это редко может быть полностью гарантировано, хотя.Если вы используете eclipse, вы можете сгенерировать
equals()
иhashCode()
использовать:Используя эту функцию, вы можете решить, какие поля вы хотите использовать для вычисления равенства и хеш-кода, и Eclipse генерирует соответствующие методы.
источник
Там хорошая реализация из Эффективное Java «s
hashcode()
иequals()
логики в Apache Commons Lang . Оформить заказ HashCodeBuilder и EqualsBuilder .источник
Objects
класс предоставляетhash(Object ..args)
&equals()
методы из Java7 на. Они рекомендуются для любых приложений, использующих jdk 1.7+IdentityHashMap
). FWIW Я использую хэш-код на основе идентификатора и равняется для всех сущностей.Просто быстрое примечание для завершения другого более подробного ответа (в терминах кода):
Если я рассмотрю вопрос « как сделать-я-создать-хэш-таблицу-в-java» и, в частности, статью «Часто задаваемые вопросы по jGuru» , я считаю, что существуют другие критерии, по которым можно судить о хэш-коде:
источник
Если я правильно понимаю ваш вопрос, у вас есть собственный класс коллекции (т. Е. Новый класс, который выходит из интерфейса Collection), и вы хотите реализовать метод hashCode ().
Если ваш класс коллекции расширяет AbstractList, вам не нужно об этом беспокоиться, уже есть реализация equals () и hashCode (), которая работает путем перебора всех объектов и добавления их hashCodes () вместе.
Теперь, если то, что вы хотите, является наилучшим способом вычисления хеш-кода для определенного класса, я обычно использую оператор ^ (побитовый исключающий или) для обработки всех полей, которые я использую в методе equals:
источник
@ about8: там довольно серьезная ошибка.
тот же хэш-код
Вы, вероятно, хотите что-то вроде
(Вы можете получить hashCode непосредственно из int в Java в эти дни? Я думаю, что это делает автокастинг ... если это так, пропустите toString, это уродливо.)
источник
foo
иbar
приводит к тому жеhashCode
. ВашtoString
AFAIK не компилируется, и если он это делает, то он ужасно неэффективен. Нечто подобное109 * getFoo().hashCode() + 57 * getBar().hashCode()
быстрее, проще и не вызывает ненужных столкновений.Поскольку вы специально спрашивали о коллекциях, я хотел бы добавить аспект, о котором другие ответы еще не упомянули: HashMap не ожидает, что их ключи изменят свой хэш-код после добавления в коллекцию. Победил бы всю цель ...
источник
Используйте методы отражения в Apache Commons EqualsBuilder и HashCodeBuilder .
источник
Я использую крошечную оболочку,
Arrays.deepHashCode(...)
потому что она правильно обрабатывает массивы, предоставленные в качестве параметровисточник
Любой метод хэширования, который равномерно распределяет значение хеша по возможному диапазону, является хорошей реализацией. См эффективной Java ( http://books.google.com.au/books?id=ZZOiqZQIbRMC&dq=effective+java&pg=PP1&ots=UZMZ2siN25&sig=kR0n73DHJOn-D77qGj0wOxAxiZw&hl=en&sa=X&oi=book_result&resnum=1&ct=result ), есть хороший наконечник там для реализации хэш-кода (пункт 9, я думаю ...).
источник
Я предпочитаю использовать служебные методы из библиотеки Google Collections lib из класса Objects, которые помогают мне поддерживать мой код в чистоте. Очень часто
equals
иhashcode
методы делаются из шаблона IDE, поэтому они не чисты для чтения.источник
Вот еще одна демонстрация подхода JDK 1.7+ с учетом логики суперкласса. Я считаю это довольно удобным с учетом класса Object hashCode (), чистой зависимости JDK и без дополнительной ручной работы. пожалуйста, обратите внимание
Objects.hash()
что допускается нулевое значение.Я не включил никакой
equals()
реализации, но в действительности это вам, конечно, понадобится.источник
Стандартная реализация слаба, и ее использование приводит к ненужным конфликтам. Представь себе
Сейчас,
и
имеют то же значение
hashCode
,31*(a+b) + c
что и множитель, используемый дляList.hashCode
получает здесь повторно. Очевидно, что столкновения неизбежны, но создание ненужных столкновений просто ... ненужно.Там нет ничего существенно умного в использовании
31
. Множитель должен быть нечетным, чтобы избежать потери информации (любой четный множитель теряет по меньшей мере самый старший бит, кратные четыре теряют два и т. Д.). Любой нечетный множитель можно использовать. Маленькие множители могут привести к более быстрым вычислениям (JIT может использовать сдвиги и дополнения), но, учитывая, что умножение имеет задержку в три цикла на современных Intel / AMD, это вряд ли имеет значение. Маленькие множители также приводят к большему столкновению для небольших входов, что иногда может быть проблемой.Использовать простое число бессмысленно, поскольку простые числа не имеют смысла в кольце Z / (2 ** 32).
Поэтому я бы рекомендовал использовать случайно выбранное большое нечетное число (не стесняйтесь брать простое число). Поскольку процессоры i86 / amd64 могут использовать более короткую инструкцию для подстановки операндов в один байт со знаком, то для множителей, подобных 109, есть небольшое преимущество в скорости. Для минимизации коллизий возьмите что-то вроде 0x58a54cf5.
Использование разных множителей в разных местах полезно, но, вероятно, недостаточно для оправдания дополнительной работы.
источник
При объединении хеш-значений я обычно использую метод объединения, который используется в библиотеке boost c ++, а именно:
Это делает довольно хорошую работу по обеспечению равномерного распределения. Для некоторого обсуждения того, как работает эта формула, смотрите сообщение StackOverflow: Магическое число в boost :: hash_combine
Хорошее обсуждение различных хеш-функций: http://burtleburtle.net/bob/hash/doobs.html
источник
Для простого класса часто проще всего реализовать hashCode () на основе полей класса, которые проверяются реализацией equals ().
Наиболее важным является сохранение согласованности между hashCode () и equals (): если equals () возвращает true для двух объектов, то hashCode () должна возвращать одно и то же значение. Если equals () возвращает false, то hashCode () должен возвращать разные значения.
источник
("abc"+""=="ab"+"c"=="a"+"bc"==""+"abc")
. Это серьезный недостаток. Было бы лучше оценить хеш-код для обоих полей, а затем рассчитать их линейную комбинацию (предпочтительно с использованием простых чисел в качестве коэффициентов).foo
иbar
производит ненужные столкновения тоже.