Оператор ==, метод равенства и метод hashCode в Java

1. Оператор ==

== — это оператор в Java, используемый для сравнения двух объектов, но при сравнении двух объектов его необходимо обсуждать в зависимости от типа сравнения.

1.1 Базовые типы данных и базовые типы данных

При сравнении базовых типов данных через == их размеры сравниваются напрямую, независимо от их конкретных типов.

short num1 = 20000;
int num2 = 20000;
System.out.println(num1 == num2); // Output: true

1.2 Ссылочные типы и ссылочные типы

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

public class Test {
    public static void main(String[] args) {
        Obj o1 = new Obj();
        Obj o2 = new Obj();
        System.out.println(o1 == o2); // Output: false
    }
}

class Obj {}

Но не во всех ситуациях возвращается false.Ссылочные типы базовых типов данных имеют механизм пула констант, так что даже если это два объекта, они все равно будут указывать на одно и то же пространство памяти, то есть они по-прежнему являются одним и тем же объектом.

Integer num1 = 100, num2 = 100;
System.out.println(num1 == num2); // Output: true

Подробную информацию см.: Восемь основных типов и типы их упаковки.

1.3 Основные типы данных и ссылочные типы

При сравнении базовых типов данных и ссылочных типов, если ссылочный тип является числовым, сравнение можно выполнить. Другие типы сравнивать нельзя, и будет сообщено об ошибке.

Integer num1 = 200;
int num2 = 200;
System.out.println(num1 == num2); // Output: true

int num = 200;
String str = "123";
System.out.println(str == num); // Error: 二元运算符 '==' 的操作数类型错误

2. метод равенства

«Равно» — это базовый метод ссылочных типов Java. Без его переопределения метод «равно» по умолчанию сравнивает адреса памяти двух объектов. После переопределения это зависит от конкретной ситуации.

String str1 = "1";
String str2 = "2";
System.out.println(str1.equals(str2)); // Output: false

2.1 Разница между методом равенства и оператором ==

  • == — оператор, равно — метод объекта (поэтому базовый тип данных отсутствует);
  • == При сравнении базовых типов данных — сравниваемое значение, при сравнении объектов — сравнение его адреса в памяти;
  • По умолчанию «равно» (не переопределяется) — это адрес памяти объекта сравнения, а после переопределения — другое содержимое (например, String — это значение содержимого, представленного объектом).

3. метод хэш-кода

HashCode — это совершенно специальный метод, который предполагает знание хеш-таблиц. Hash переводится как хэш. Это алгоритм, который позволяет быстро преобразовать любой объект в шестнадцатеричное значение. Между разными объектами существует высокая вероятность того, что хеш-значения полученные с помощью алгоритма хеширования, не будут одинаковыми. Существует очень небольшая вероятность того, что они будут одинаковыми. В это время возникает ситуация, называемая «конфликтом хеширования». Здесь мы, не вдаваясь в подробности, см.: Хеш Подробности алгоритма .

Короче говоря, при отсутствии «хеш-конфликта» мы можем судить, являются ли два объекта одним и тем же объектом, по разным значениям хеш-функции разных объектов.

String str1 = "1";
String str2 = "2";
System.out.println(str1.hashCode() == str2.hashCode()); // Output: false

Конечно, в обычных обстоятельствах мы не будем использовать описанный выше метод hashCode, поскольку нет никакой гарантии, что не возникнут «конфликты хэшей». Хотя хеш-значения разных объектов могут быть одинаковыми, разница в хеш-значениях двух объектов означает, что они должны быть разными! Следовательно, значение хеш-функции можно использовать для определения того, равны ли два объекта.

4. Различия и связи

4.1 Различия

== обычно используется для определения равенства чисел, Equals обычно используется для определения равенства двух объектов, а hashCode обычно используется для определения того, являются ли два объекта неравными.

== только сравнивает числа и является самым быстрым для оценки.Кроме того, это метод hashCode, потому что вычисление хэш-значений происходит очень быстро.Наконец, равно.По умолчанию метод равно сравнивает адреса памяти двух объектов.Хотя этот процесс очень быстрый. Более общая ситуация заключается в том, что метод равенства был переопределен и сравнивает значения свойств двух объектов нечислового типа, поэтому он является самым медленным.

String str1 = "1";
String str2 = "1";
System.out.println(str1.equals(str2)); // Output: true

В приведенном выше коде встроенный в Java ссылочный тип String переопределяет метод равенства, который сравнивает содержимое двух объектов String, а не адреса памяти.

4.2 Контакт

== обычно не имеет ничего общего с равенствами и hashCode.С определенной точки зрения, не существует неизбежной связи между равенствами и hashCode. Но в Java есть структура данных, которая связывает равенства и hashCode, то есть HashMap и его подклассы.

Ключи в HashMap не могут повторяться, поэтому его ключи должны быть разными объектами. В это время для сравнения используется hashCode, который быстро вычисляет. Если значения хеша не равны, то два объекта не должны быть равны., если они равны, то для этого есть две возможности. Одна ситуация заключается в том, что два объекта действительно равны, а другая ситуация заключается в том, что возникает редкое явление «хэш-конфликта», тогда наступает очередь равенства. на этот раз Пришло время судить! Таким образом, проблема неповторяющихся ключей решается эффективно и быстро.

Из сравнения HashMap выше мы также видим, что когда мы настраиваем тип, если мы хотим переписать метод равенства или метод hashCode, перепишите их оба одновременно, потому что встроенная структура данных Java HashMap определяет, будет ли ключ в том, что дублирование требует вызова обоих из них одновременно.

Подводя итог, мы можем свести это в следующую таблицу:

метод сравнения == оператор метод равенства метод хэш-кода
сравнить скорость быстрый Быстро по умолчанию, медленно в целом середина
сравнительное значение численная величина По умолчанию используется адрес памяти, обычно атрибут объекта. хэш-значение

4.3 Классические задачи

Почему я должен переписывать метод равенства после переопределения метода hashCode? Возникнет ли проблема, если я переопределю только метод равенства, но не метод hashCode? Как это отражается в HashMap?

В HashMap ключи не могут повторяться, то есть их ключи разные, поэтому необходимо определить, являются ли разные объекты одним и тем же объектом. Чтобы решить эту проблему, HashMap вызывает для оценки метод равенства и метод hashCode объекта. Часть исходного кода для решения выглядит следующим образом:

if (e.hash == hash &&
    ((k = e.key) == key || (key != null && key.equals(k))))
    return e;

И метод hashCode, и метод Equals можно использовать для сравнения двух объектов, но между ними есть некоторые различия:

метод сравнения метод равенства метод хэш-кода
сравнить скорость

По умолчанию адреса памяти сравниваются, что происходит быстро;

После переписывания контент обычно сравнивается и скорость низкая.

Быстро рассчитать хеш-значения
сравнительное значение Адрес памяти или содержимое (атрибут) хэш-значение

Поэтому сначала используйте для сравнения хэш-код с быстрой скоростью расчета, который может решить большинство проблем. Однако из-за возможности «конфликта хэшей» для его решения также необходим метод равенства.

Просто потому, что метод Equals и метод hashCode необходимо вызывать одновременно, чтобы определить, повторяется ли ключ, мы должны переписать их оба вместе при переписывании в определяемом нами классе. Если вы переопределяете только метод равенства, но не метод hashCode, то когда два объекта с одинаковым содержимым, но разными адресами памяти создаются и сохраняются в HashMap, они будут обрабатываться как два ключа вместо одного ключа, что приведет к другим ошибкам. .

Guess you like

Origin blog.csdn.net/weixin_62651706/article/details/132274016