О хашкоде, в Википедии:
В языке программирования Java каждый класс неявно или явно предоставляет метод HashCode (), который переваривает данные, хранящиеся в экземпляре класса в единое хэш-значение (32-битное подписанное целое число).
HashCode извлекает 32-разрядное целое число на основе всех данных, хранящихся в экземпляре объекта. Цель этого целого числа состоит в том, чтобы указать уникальность экземпляра. Это несколько похоже на код MD5, и каждый файл может генерировать уникальный код MD5 через алгоритм MD5. Тем не менее, хэшкод в Java на самом деле не реализует хешкод для создания уникального хэшкода для каждого объекта, и все еще есть определенные шансы на дублирование.
Давайте сначала посмотрим на класс объекта. Мы знаем, что класс объектов является прямым или косвенным родительским классом всех классов в программе Java и находится в самой высокой точке уровня класса. Многие общие методы определены в классе объектов, включая метод хэшкода, о котором мы хотим поговорить, следующим образом
публичный финальный класс нативного <?> getClass (); общественный родной int hashcode (); public boolean equals (Object obj) {return (this == obj); } public String toString () {return getClass (). getName () + "@" + integer.tohexstring (hashcode ()); }Обратите внимание, что перед методом HashCode существует собственный модификатор, что означает, что метод хэшкода реализован на языке не-ява. Конкретный метод реализуется извне и возвращает адрес объекта памяти.
Во многих классах Java равенство и хешкодные методы переписаны. Почему это? Наиболее распространенный класс строк, например, если я определяю две строки с одинаковыми символами, то при сравнении их, результат, который я хочу, должен быть равным. Если вы не переопределяете методы равных и хэшкодов, они определенно не будут равны, потому что адреса памяти двух объектов разные.
public int hashcode () {int h = hash; if (h == 0) {int off = offset; char val [] = value; int len = count; for (int i = 0; i <len; i ++) {h = 31*h+val [off ++]; } hash = h; } return h; }Фактически, этот код является реализацией этого математического выражения
S [0]*31^(n-1) + s [1]*31^(n-2) +… + s [n-1]
S [i]-это i-й символ строки, а n-длина строки. Тогда зачем использовать 31 здесь вместо других чисел? Эффективная Java говорит об этом: причина, по которой 31 выбран, заключается в том, что это странное главное число. Если множитель является равномерным числом и переполнено умножением, информация будет потеряна, поскольку умножение на 2 эквивалентно операции сдвига. Преимущества использования основных чисел не очевидны, но результаты хеш обычно используются для расчета результатов хэш. 31 имеет хорошую функцию, которая состоит в том, чтобы использовать сдвиг и вычитание вместо умножения, чтобы получить лучшую производительность: 31*i == (i << 5) -i. VMS может автоматически завершить эту оптимизацию.
Как вы можете видеть, класс строки использует значение своего значения в качестве параметра для расчета хэшкода, то есть то же значение определенно будет иметь такое же значение хэшкода. Это также легко понять, поскольку значения значений одинаковы, поэтому, если сравнение равных также равно, метод равных равен, то хэшкод должен быть равным. Другой путь не обязательно верен. Это не гарантирует, что тот же хэшкод должен иметь тот же объект.
Хорошая хэш -функция должна выглядеть так: производить неравные хешкоды для разных объектов.
В идеальных случаях функция хеш должна равномерно распределять неравные экземпляры в наборе всех возможных хэш -кодов. Очень трудно достичь этой идеальной ситуации, по крайней мере, Java не достигла этого. Потому что мы видим, что хэшкод генерируется неровно, и он имеет определенные правила, которые являются математическим уравнением выше. Мы можем построить некоторые, которые имеют одинаковый хэшкод, но различные значения значений, например: хэшкод AA и BB одинаковы.
Следующий код:
открытый класс main {public static void main (string [] args) {main m = new main (); System.out.println (m); System.out.println (integer.tohexstring (m.hashcode ())); Строка a = "aa"; Строка b = "bb"; System.out.println (a.hashcode ()); System.out.println (b.hashcode ()); }}Результат вывода:
Main@2a139a55 2a139a55 2112 2112
Как правило, при переписывании равной функции вам также необходимо переписать функцию HashCode. Почему это?
Давайте посмотрим на этот пример, давайте создадим простой классной сотрудника
Сотрудник открытого класса {частное целочисленное идентификатор; частная строка FirstName; частная строка Lastname; частное отделение строк; public integer getId () {return id; } public void setId (Integer id) {this.id = id; } public String getFirstName () {return FirstName; } public void setFirstName (String FirstName) {this.FirstName = FirstName; } public String getLastName () {return LastName; } public void setlastName (String lastname) {this.lastName = lastName; } public String getDepartment () {return Department; } public void setDepartment (String Department) {this.Department = Департамент; }}У класса работников выше есть только некоторые основные свойства, гетры и сеттеры. Теперь рассмотрим ситуацию, когда вам нужно сравнить двух сотрудников.
public class ровный {public static void main (string [] args) {employtee e1 = new employee (); Сотрудник E2 = новый сотрудник (); e1.setid (100); e2.setid (100); // печатает false в консольной системе.out.println (e1.equals (e2)); }}Нет сомнений в том, что вышеупомянутая программа вызовет ложные, но на самом деле вышеупомянутые два объекта представляют через сотрудника. Настоящая бизнес -логика надеется, что мы вернемся.
Чтобы достичь этого, нам нужно переписать метод равных.
public boolean equals (object o) {if (o == null) {return false; } if (o == this) {return true; } if (getClass ()! = o.getClass ()) {return false; } Сотрудник e = (сотрудник) o; return (this.getid () == e.getid ());} Добавьте этот метод в вышеупомянутый класс, и eauqlstest выведет true.
Так мы сделали? Нет, давайте изменим метод испытания и посмотрим.
import java.util.HashSet;import java.util.Set;public class EqualsTest{public static void main(String[] args) {Employee e1 = new Employee();Employee e2 = new Employee();e1.setId(100);e2.setId(100);//Prints 'true'System.out.println(e1.equals(e2));Set<Employee> employees = новый хэшсет <mempleatee> (); effectian.Add (e1); сотрудники.add (e2); // печатает два объекта.Вышеуказанная программа выводит два результата. Если два объекта сотрудника равны возвращению TRUE, только один объект должен храниться в наборе. В чем проблема?
Мы забыли второй важный метод HashCode (). Так же, как сказал Javadoc из JDK, если вы переписываете метод equals (), вы должны переписать метод HashCode (). Давайте добавим следующий метод, и программа будет выполняться правильно.
@Override public int hashcode () {final int prime = 31; int result = 1; result = prime * result + getId (); результат возврата; }Вещи, чтобы помнить
Постарайтесь убедиться, что одно и то же свойство объекта используется для генерации двух методов: hashcode () и equals (). В нашем случае мы используем идентификаторы сотрудников.
Метод eqauls должен быть согласованным (если объект не изменен, равные должны вернуть одно и то же значение)
В любое время, пока a.equals (b), a.hashcode () должен быть равным B.hashcode ().
Оба должны быть переписаны одновременно.
Суммировать
Вышеуказанное все о глубоком понимании этой статьи о методе хэшкодов в Java, и я надеюсь, что это будет полезно для всех. Заинтересованные друзья могут продолжать ссылаться на другие связанные темы на этом сайте. Если есть какие -либо недостатки, пожалуйста, оставьте сообщение, чтобы указать это. Спасибо, друзья, за вашу поддержку на этом сайте!