Рубрики
Без рубрики

Java равно() и хэш-код()

Java equals(), хэш-код Java(), функции Java equals и хэш-кода, Как реализовать методы java equals() и хэш-кода (), метод equals в java, метод хэш-кода в java, метод переопределения Java равен, метод переопределения хэш-кода Java.

Автор оригинала: Pankaj Kumar.

Методы Java equals() и hashCode() присутствуют в классе объектов. Таким образом, каждый класс java получает реализацию по умолчанию equals() и hashCode(). В этом посте мы подробно рассмотрим методы java equals() и hashCode ().

Java равно()

Класс объектов, определенный методом equals (), выглядит следующим образом:

public boolean equals(Object obj) {
        return (this == obj);
}

Согласно документации java по методу equals (), любая реализация должна соответствовать следующим принципам.

  • Для любого объекта x x.равно(x) должно возвращать true .
  • Для любых двух объектов x и y x.равно(y) должно возвращать true тогда и только тогда, когда y.равно(x) возвращает true .
  • Для нескольких объектов x, y и z, если x.равно(y) возвращает true и y.равно(z) возвращает true , то x.равно(z) должно возвращать true .
  • Несколько вызовов x.equals(y) должны возвращать один и тот же результат, если только не изменено какое-либо из свойств объекта, которое используется в реализации метода equals () .
  • Реализация метода Object class equals() возвращает true только в том случае, если обе ссылки указывают на один и тот же объект.

Хэш-код Java()

Хэш-код объекта Java() является собственным методом и возвращает целочисленное значение хэш-кода объекта. Общий контракт метода hashCode() заключается в:

  • Несколько вызовов hashCode() должны возвращать одно и то же целочисленное значение, если только не изменено свойство объекта, используемое в методе equals ().
  • Значение хэш-кода объекта может изменяться при нескольких исполнениях одного и того же приложения.
  • Если два объекта равны в соответствии с методом equals (), то их хэш-код должен быть одинаковым.
  • Если два объекта неравны в соответствии с методом equals (), их хэш-код не обязательно должен отличаться. Их значение хэш-кода может быть или не быть равным.

Важность метода equals() и хэш-кода()

Метод Java hashCode() и equals() используются в реализациях на основе хэш-таблиц в java для хранения и извлечения данных. Я подробно объяснил это в разделе “Как работает HashMap в java”?

Реализация equals() и hashCode() должна соответствовать этим правилам.

  • Если o1.равно(o2) , то o1.Хэш-код().Хэш-код() всегда должен быть истинным .
  • Если o1.hashCode().hashCode истинно, это не означает, что o1.равно(o2) будет истинно .

Когда переопределять методы equals() и hashCode ()?

Когда мы переопределяем метод equals (), почти необходимо переопределить и метод hashCode (), чтобы наша реализация не нарушила их контракт.

Обратите внимание, что ваша программа не будет выдавать никаких исключений, если контракт equals() и hashCode() нарушен, если вы не планируете использовать класс в качестве ключа хэш-таблицы, то это не создаст никаких проблем.

Если вы планируете использовать класс в качестве ключа хэш-таблицы, то необходимо переопределить методы equals() и hashCode ().

Давайте посмотрим, что происходит, когда мы полагаемся на реализацию методов equals() и hashCode() по умолчанию и используем пользовательский класс в качестве ключа HashMap.

package com.journaldev.java;

public class DataKey {

	private String name;
	private int id;

        // getter and setter methods

	@Override
	public String toString() {
		return "DataKey [name=" + name + ", id=" + id + "]";
	}

}
package com.journaldev.java;

import java.util.HashMap;
import java.util.Map;

public class HashingTest {

	public static void main(String[] args) {
		Map hm = getAllData();

		DataKey dk = new DataKey();
		dk.setId(1);
		dk.setName("Pankaj");
		System.out.println(dk.hashCode());

		Integer value = hm.get(dk);

		System.out.println(value);

	}

	private static Map getAllData() {
		Map hm = new HashMap<>();

		DataKey dk = new DataKey();
		dk.setId(1);
		dk.setName("Pankaj");
		System.out.println(dk.hashCode());

		hm.put(dk, 10);

		return hm;
	}

}

Когда мы запустим вышеуказанную программу, она выведет null . Это связано с тем, что метод хэш-кода объекта() используется для поиска корзины для поиска ключа. Поскольку у нас нет доступа к ключам HashMap, и мы снова создаем ключ для извлечения данных, вы заметите, что значения хэш-кода обоих объектов различны, и, следовательно, значение не найдено.

Реализация метода equals() и хэш-кода()

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

Мы можем использовать Eclipse для автоматической генерации методов equals() и hashCode ().

Вот автоматически сгенерированные реализации методов equals() и hashCode ().

@Override
public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result + id;
	result = prime * result + ((name == null) ? 0 : name.hashCode());
	return result;
}

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

Обратите внимание, что оба метода equals() и hashCode() используют одни и те же поля для вычислений, поэтому их контракт остается действительным.

Если вы снова запустите тестовую программу, мы получим объект с карты, и программа напечатает 10.

Мы также можем использовать Project Lombok для автоматической генерации эквивалентов и реализации метода хэш-кода.

Что такое столкновение хэшей

Говоря очень простыми словами, реализации хэш-таблиц Java используют следующую логику для операций get и put.

  1. Сначала определите “корзину” для использования, используя хэш-код “ключа”.
  2. Если в корзине нет объектов с одинаковым хэш-кодом, добавьте объект для операции put и верните значение null для операции get.
  3. Если в корзине есть другие объекты с тем же хэш-кодом, то в игру вступает метод “ключ” равен.
    • Если функция equals() возвращает true и это операция put, то значение объекта переопределяется.
    • Если функция equals() возвращает false и это операция put, то в корзину добавляется новая запись.
    • Если функция equals() возвращает true и это операция get, то возвращается значение объекта.
    • Если функция equals() возвращает false и это операция get, то возвращается значение null.

На рисунке ниже показаны элементы корзины HashMap и то, как связаны их значения() и хэш-код ().

Явление, когда два ключа имеют одинаковый хэш-код, называется столкновением хэшей. Если метод hashCode() не реализован должным образом, произойдет большее количество столкновений хэшей, и записи карты не будут правильно распределены, что приведет к замедлению операций получения и размещения. Это является причиной использования простых чисел при генерации хэш-кода, чтобы записи карты правильно распределялись по всем сегментам.

Что делать, если мы не реализуем как hashCode (), так и equals()?

Мы уже видели выше, что если hashCode() не реализован, мы не сможем получить значение, потому что HashMap использует хэш-код для поиска корзины для поиска записи.

Если мы используем только хэш-код() и не реализуем функцию equals (), то также значение не будет получено, потому что метод equals() вернет значение false.

Рекомендации по реализации методов equals() и hashCode()

  • Используйте одни и те же свойства в реализациях методов equals() и hashCode (), чтобы их контракт не нарушался при обновлении каких-либо свойств.
  • Лучше использовать неизменяемые объекты в качестве ключа хэш-таблицы, чтобы мы могли кэшировать хэш-код, а не вычислять его при каждом вызове. Вот почему строка является хорошим кандидатом на ключ хэш-таблицы, потому что она неизменна и кэширует значение хэш-кода.
  • Реализуйте метод hashCode() таким образом, чтобы происходило наименьшее количество столкновений хэшей и записи равномерно распределялись по всем сегментам.