410013796724260
• Webmoney
R335386147728
Z369087728698
Хэш-код объекта, hashCodeВ классе Object, который является родительским классом для объектов java, определен метод hashCode(), позволяющий получить уникальный целый номер для данного объекта. Когда объект сохраняют в коллекции типа HashSet, то данный номер позволяет быстро определить его местонахождение в коллекции и извлечь. Функция hashCode() объекта Object возвращает целое число int, размер которого равен 4-м байтам и значение которого располагается в диапазоне от -2 147 483 648 до 2 147 483 647. Рассмотрим простой пример HashCodeTest.java, который в консоли будет печатать значение hashCode. public class HashCodeTest { public static void main(String[] args) { int hCode = (new Object()).hashCode(); System.out.println("hashCode = " + hCode); } } Значение hashCode программы можно увидеть в консоли. hashCode = 954599881 По умолчанию, функция hashCode() для объекта возвращает номер ячейки памяти, где объект сохраняется. Поэтому, если изменение в код приложения не вносятся, то функция должна выдавать одно и то же значение. При незначительном изменении кода значение hashCode также изменится. Функция сравнения объектов equals()В родительском классе Object наряду с функцией hashCode() имеется еще и логическая функция equals(Object)/ Функция equals(Object) используется для проверки равенства двух объектов. Реализация данной функции по умолчанию просто проверяет по ссылкам два объекта на предмет их эквивалентности. Рассмотрим пример сравнения двух однотипных объектов Test следующего вида : class Test { int f1 = -1; int f2 = -1; public Test (final int f1, final int f2) { this.f1 = f1; this.f2 = f2; } public int getF1() { return this.f1; } public int getF2() { return this.f2; } } Создадим 2 объекта типа Test с одинаковыми значениями и сравним объекты с использованием функции equals(). public class EqualsExample { public static void main(String[] args) { Test obj1 = new Test(11, 12); Test obj2 = new Test(11, 12); System.out.println("Объекты :\n\tobj1 = " + obj1 + "\n\tobj2 = " + obj2); System.out.println("hashCode объектов :" + "\n\tobj1.hashCode = " + obj1.hashCode() + "\n\tobj2.hashCode = " + obj2.hashCode()); System.out.println("Сравнение объектов :" + "\n\tobj1.equals(obj2) = " + obj1.equals(obj2)); } } Результат выполнения программы будет выведен в консоль : Объекты : obj1 = example.Test@780324ff obj2 = example.Test@16721ee7 hashCode объектов : obj1.hashCode = 2013471999 obj2.hashCode = 376577767 Сравнение объектов : obj1.equals(obj2) = false Не трудно было догадаться, что результат сравнения двух объектов вернет «false». На самом деле, это не совсем верно, поскольку объекты идентичны и в real time application метод должен вернуть true. Чтобы достигнуть этого корректного поведения, необходимо переопределить метод equals() объекта Test. @Override public boolean equals(Object obj) { if (this == obj) return true; else if (obj == null) return false; else if (getClass() != obj.getClass()) return false; Test other = (Test) obj; if (f1 != other.getF1()) return false; else if (f2 != other.getF2()) return false; return true; } Вот теперь функция сравнения equals() возвращает значение «true». Достаточно ли этого? Попробуем добавить объекты в коллекцию HashSet и посмотрим, сколько объектов будет в коллекции? Для этого в в метод main примера EqualsExample добавим следующие строки : Set<Test> objects = new HashSet<Test>(); objects.add(obj1); objects.add(obj2); System.out.println("Коллекция :\n\t" + objects); Однако в коллекции у нас два объекта. Коллекция : [example.Test@780324ff, example.Test@16721ee7] Поскольку Set содержит только уникальные объекты, то внутри HashSet должен быть только один экземпляр. Чтобы этого достичь, объекты должны возвращать одинаковый hashCode. То есть нам необходимо переопределить также функцию hashCode() вместе с equals(). @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + f1; result = prime * result + f2; return result; } Вот теперь все будет корректно выполняться - для двух объектов с одинаковыми параметрами функция equals() вернет значение «true», и в коллекцию попадет только один объект. В консоль будет выведен следующий текст работы программы : Объекты : obj1 = example.Test@696 obj2 = example.Test@696 hashCode объектов : obj1.hashCode = 1686 obj2.hashCode = 1686 Сравнение объектов : obj1.equals(obj2) = true Коллекция : [example.Test@696] Таким образом, переопределяя методы hashCode() и equals() мы можем корректно управлять нашими объектами, не допуская их дублирования. Использование библиотеки commons-lang.jar для переопределения hashCode() и equals()Процесс формирования методов hashCode() и equals() в IDE Eclipse автоматизирован. Для создания данных методов необходимо правой клавишей мыши вызвать контекстное меню класса (кликнуть на классе) и выбрать пункт меню Source (Class >> Source), в результате которого будет открыто следующее окно со списком меню для класса. Выбираем пункт меню «Generate hachCode() and equals()» и в класс будут добавлены соответствующие методы. @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + f1; result = prime * result + f2; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Test other = (Test) obj; if (f1 != other.f1) return false; if (f2 != other.f2) return false; return true; } Библиотека Apache Commons включает два вспомогательных класса HashCodeBuilder и EqualsBuilder для вызова методов hashCode() и equals(). Чтобы включить их в класс необходимо внести следующие изменения. import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; ... @Override public int hashCode() { final int prime = 31; return new HashCodeBuilder(getF1()%2 == 0 ? getF1() + 1 : getF1(), prime).toHashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; else if (obj == null) return false; else if (getClass() != obj.getClass()) return false; Test other = (Test) obj; return new EqualsBuilder().append(getF1(),other.getF1()).isEquals(); } Примечание : желательно в методах hashCode() и equals() не использовать ссылки на поля, заменяйте их геттерами. Это связано с тем, что в некоторых технологиях java поля загружаются при помощи отложенной загрузки (lazy load) и не доступны, пока не вызваны их геттеры. Скачать примерИсходный код рассмотренного примера в виде проекта Eclipse можно скачать здесь (263 Kб). |