Что такое код equalrect

Содержание

Что такое код equalrect

Группа: Главные администраторы
Сообщений: 14349
Регистрация: 12.10.2007
Из: Twilight Zone
Пользователь №: 1

Я недавно начал заниматься программированием, и в этой области для меня много нового. Данная статья рассчитана на начинающих java-программистов, и, надеюсь, поможет в освоении излюбленной темы для собеседований “hashCode и equals”.

Хочу сразу предостеречь, что я не являюсь экспертом в данной теме и могу что-то не так понимать, поэтому, если вы нашли ошибку или неточность — свяжитесь со мной.

Что такое хеш-код?

Если очень просто, то хеш-код — это число. На самом деле просто, не так ли? Если более точно, то это битовая строка фиксированной длины, полученная из массива произвольной длины (википедия).

Выполним следующий код:

public class Main <
public static void main(String[] args) <
Object object = new Object();
int hCode;
hCode = object.hashCode();
System.out.println(hCode);
>
>

В результате выполнения программы в консоль выведется целое 10-ти значное число. Это число и есть наша битовая строка фиксированной длины. В java она представлена в виде числа примитивного типа int, который равен 4-м байтам, и может помещать числа от -2 147 483 648 до 2 147 483 647. На данном этапе важно понимать, что хеш-код это число, у которого есть свой предел, который для java ограничен примитивным целочисленным типом int.

Вторая часть объяснения гласит:

полученная из массива произвольной длины.

Под массивом произвольной длины мы будем понимать объект. В 1 примере в качестве массива произвольной длины у нас выступает объект типа Object.

В итоге, в терминах Java, хеш-код — это целочисленный результат работы метода, которому в качестве входного параметра передан объект.

Этот метод реализован таким образом, что для одного и того-же входного объекта, хеш-код всегда будет одинаковым. Следует понимать, что множество возможных хеш-кодов ограничено примитивным типом int, а множество объектов ограничено только нашей фантазией. Отсюда следует утверждение: “Множество объектов мощнее множества хеш-кодов”. Из-за этого ограничения, вполне возможна ситуация, что хеш-коды разных объектов могут совпасть.

Здесь главное понять, что:

  • Если хеш-коды разные, то и входные объекты гарантированно разные.
  • Если хеш-коды равны, то входные объекты не всегда равны.

Ситуация, когда у разных объектов одинаковые хеш-коды называется — коллизией. Вероятность возникновения коллизии зависит от используемого алгоритма генерации хеш-кода.

Сперва, что-бы избежать путаницы, определимся с терминологией. Одинаковые объекты — это объекты одного класса с одинаковым содержимым полей.

Понятие эквивалентности. Метод equals()

Начнем с того, что в java, каждый вызов оператора new порождает новый объект в памяти. Для иллюстрации создадим какой-нибудь класс, пускай он будет называться “BlackBox”.

Выполним следующий код:

public class BlackBox <
int a;
int b;

BlackBox(int varA, int varB) <
a = varA;
b = varB;
>
>

Создадим класс для демонстрации BlackBox.

public class DemoBlackBox <
public static void main(String[] args) <
BlackBox object1 = new BlackBox(5, 10);
BlackBox object2 = new BlackBox(5, 10);
>
>

Во втором примере, в памяти создастся два объекта.

Но, как вы уже обратили внимание, содержимое этих объектов одинаково, то есть эквивалентно. Для проверки эквивалентности в классе Object существует метод equals(), который сравнивает содержимое объектов и выводит значение типа boolean true, если содержимое эквивалентно, и false — если нет.

object1.equals(object2);// должно быть true, поскольку содержимое объектов эквивалентно

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

object1.equals(object2)// должно быть true
object1.hashCode() == object2.hashCode()// должно быть true

Я написал “должно быть”, потому что если вы выполните предыдущий пример, то на самом деле результатом выполнения всех операций будет false. Для пояснения причин, заглянем в исходные коды класса Object.

Как известно, все java-классы наследуются от класса Object. В этом классе уже определены методы hashCode() и equals().

Определяя свой класс, вы автоматически наследуете все методы класса Object. И в ситуации, когда в вашем классе не переопределены (@overriding) hashCode() и equals(), то используется их реализация из Object.

Рассмотрим исходный код метода equals() в классе Object.

public boolean equals(Object obj) <
return (this == obj);
>

При сравнение объектов, операция “==” вернет true лишь в одном случае — когда ссылки указывают на один и тот-же объект. В данном случае не учитывается содержимое полей.

Выполнив приведённый ниже код, equals вернет true.

public class DemoBlackBox <
public static void main(String[] args) <
BlackBox object3 = new BlackBox(5, 10);
BlackBox object4 = object3;// Переменная object4 ссылается на
//тот-же объект что и переменная object3
object3.equals(object4)//true
>
>

Теперь понято, почему Object.equals() работает не так как нужно, ведь он сравнивает ссылки, а не содержимое объектов.

Далее на очереди hashCode(), который тоже работает не так как полагается.

Заглянем в исходный код метода hashCode() в классе Object:

public native int hashCode();

Вот собственно и вся реализация. Ключевое слово native означает, что реализация данного метода выполнена на другом языке, например на C, C++ или ассемблере. Конкретный native int hashCode() реализован на C++, вот исходники — http://hg.openjdk.java.net/jdk7/jdk7/hotsp. ynchronizer.cpp функция get_next_hash.

При вычислении хэш-кода для объектов класса Object по умолчанию используется Park-Miller RNG алгоритм. В основу работы данного алгоритма положен генератор случайных чисел. Это означает, что при каждом запуске программы у объекта будет разный хэш-код.

Получается, что используя реализацию метода hashCode() от класса Object, мы при каждом создании объекта класса new BlackBox(), будем получать разные хеш-коды. Мало того, перезапуская программу, мы будем получать абсолютно разные значения, поскольку это просто случайное число.

Но, как мы помним, должно выполняться правило: “если у двух объектов одного и того же класса содержимое одинаковое, то и хеш-коды должны быть одинаковые ”. Поэтому, при создании пользовательского класса, принято переопределять методы hashCode() и equals() таким образом, что бы учитывались поля объекта.

Это можно сделать вручную либо воспользовавшись средствами генерации исходного кода в IDE. Например, в Eclipse это Source в†’ Generate hashCode() and equals().

В итоге, класс BlackBox приобретает вид:

public class BlackBox <
int a;
int b;

BlackBox(int varA, int varB) <
a = varA;
b = varB;
>

@Override
public int hashCode() <
final int prime = 31;
int result = 1;
result = prime * result + varA;
result = prime * result + varB;
return result;
>

@Override
public boolean equals(Object obj) <
if (this == obj)
return true;
if (obj == null)
return false;
if (get > return false;
BlackBox other = (BlackBox) obj;
if (varA != other.varA)
return false;
if (varB != other.varB)
return false;
return true;
>
>

Теперь методы hashCode() и equals() работают корректно и учитывают содержимое полей объекта:

Кому интересно переопределение в ручную, можно почитать Effective Java — Joshua Bloch, chapter 3, item 8,9.

Object. Equals Метод

Определение

Определяет, равны ли два экземпляра объекта. Determines whether two object instances are equal.

Перегрузки

Определяет, равен ли заданный объект текущему объекту. Determines whether the specified object is equal to the current object.

Определяет, считаются ли равными указанные экземпляры объектов. Determines whether the specified object instances are considered equal.

Equals(Object)

Определяет, равен ли заданный объект текущему объекту. Determines whether the specified object is equal to the current object.

Параметры

Объект, который требуется сравнить с текущим объектом. The object to compare with the current object.

Возвраты

Значение true , если указанный объект равен текущему объекту; в противном случае — значение false . true if the specified object is equal to the current object; otherwise, false .

Примеры

Point В следующем примере показан класс, который Equals переопределяет метод, чтобы обеспечить равенство Point3D значений, и класс, производный Point от. The following example shows a Point class that overrides the Equals method to provide value equality, and a Point3D class that is derived from Point . Поскольку Point Object.Equals(Object) переопределения Object.Equals(Object) для проверки равенства значений, метод не вызывается. Because Point overrides Object.Equals(Object) to test for value equality, the Object.Equals(Object) method is not called. Point3D.Equals Однако вызывается Point.Equals , Point поскольку Object.Equals(Object) реализуется способом, предоставляющим равенство значений. However, Point3D.Equals calls Point.Equals because Point implements Object.Equals(Object) in a manner that provides value equality.

Метод проверяет, что аргумент не равен null и ссылается на экземпляр того же типа, что и этот объект. **** obj Point.Equals The Point.Equals method checks to make sure that the obj argument is not null and that it references an instance of the same type as this object. Если проверка завершается ошибкой, метод возвращает false значение. If either check fails, the method returns false .

Point.Equals МетодGetType вызывает метод, чтобы определить, идентичны ли типы времени выполнения двух объектов. The Point.Equals method calls the GetType method to determine whether the run-time types of the two objects are identical. Если метод obj is Point использовал проверку формы в C# или TryCast(obj, Point) Visual Basic, проверка вернется true в Point случаях, когда obj является экземпляром производного класса, obj хотя и текущий экземпляр имеет разные типы времени выполнения. If the method used a check of the form obj is Point in C# or TryCast(obj, Point) in Visual Basic, the check would return true in cases where obj is an instance of a derived class of Point , even though obj and the current instance are not of the same run-time type. Убедившись, что оба объекта имеют одинаковый тип, метод приводится obj к типу Point и возвращает результат сравнения полей экземпляров двух объектов. Having verified that both objects are of the same type, the method casts obj to type Point and returns the result of comparing the instance fields of the two objects.

В Point3D.Equals унаследованный Point.Equals метод, который переопределяет Object.Equals(Object), вызывается до того, как все еще выполняется. In Point3D.Equals , the inherited Point.Equals method, which overrides Object.Equals(Object), is invoked before anything else is done. Поскольку Point3D является запечатанным классом NotInheritable (в Visual Basic), проверка формы obj is Point в C# TryCast(obj, Point) Point3D или в Visual Basic достаточно, чтобы гарантировать, что obj является объектом. Because Point3D is a sealed class ( NotInheritable in Visual Basic), a check in the form obj is Point in C# or TryCast(obj, Point) in Visual Basic is adequate to ensure that obj is a Point3D object. Если это Point Equalsобъект, он приводится к объекту и передается в реализацию базового класса. Point3D If it is a Point3D object, it is cast to a Point object and passed to the base class implementation of Equals. Только при возврате Point.Equals true унаследованного метода метод сравнивает z поля экземпляра, представленные в производном классе. Only when the inherited Point.Equals method returns true does the method compare the z instance fields introduced in the derived class.

В следующем примере определяется Rectangle класс, который внутренне реализует прямоугольник как два Point объекта. The following example defines a Rectangle class that internally implements a rectangle as two Point objects. Класс также переопределяет Object.Equals(Object) , чтобы обеспечить равенство значений. Rectangle The Rectangle class also overrides Object.Equals(Object) to provide for value equality.

Некоторые языки, такие C# как и Visual Basic, поддерживают перегрузку операторов. Some languages such as C# and Visual Basic support operator overloading. Если тип перегружает оператор равенства, он также должен переопределять Equals(Object) метод, чтобы обеспечить ту же функциональность. When a type overloads the equality operator, it must also override the Equals(Object) method to provide the same functionality. Обычно это достигается путем написания Equals(Object) метода с точки зрения перегруженного оператора равенства, как показано в следующем примере. This is typically accomplished by writing the Equals(Object) method in terms of the overloaded equality operator, as in the following example.

Поскольку Complex является типом значения, он не может быть производным от. Because Complex is a value type, it cannot be derived from. Поэтому Equals(Object) методу переопределения метода не требуется вызывать GetType для определения точного типа времени выполнения каждого объекта, is но вместо этого можно использовать оператор в C# или TypeOf оператор в Visual Basic, чтобы проверить тип obj параметр. Therefore, the override to Equals(Object) method need not call GetType to determine the precise run-time type of each object, but can instead use the is operator in C# or the TypeOf operator in Visual Basic to check the type of the obj parameter.

Комментарии

Тип сравнения текущего экземпляра и obj параметра зависит от того, является ли текущий экземпляр ссылочным типом или типом значения. The type of comparison between the current instance and the obj parameter depends on whether the current instance is a reference type or a value type.

Если текущий экземпляр является ссылочным типом, Equals(Object) метод проверяет равенство ссылок, а вызов Equals(Object) метода эквивалентен вызову ReferenceEquals метода. If the current instance is a reference type, the Equals(Object) method tests for reference equality, and a call to the Equals(Object) method is equivalent to a call to the ReferenceEquals method. Равенство ссылок означает, что сравниваемые объектные переменные ссылаются на один и тот же объект. Reference equality means that the object variables that are compared refer to the same object. В следующем примере показан результат такого сравнения. The following example illustrates the result of such a comparison. Он Person определяет класс, который является ссылочным типом, и Person вызывает конструктор класса для создания экземпляров двух новых Person объектов person1a и, имеющих одно person2 и то же значение. It defines a Person class, which is a reference type, and calls the Person class constructor to instantiate two new Person objects, person1a and person2 , which have the same value. Она также назначается person1a другой объектной переменной, person1b . It also assigns person1a to another object variable, person1b . Как показано в выходных данных примера, и person1a person1b равны, так как они ссылаются на один и тот же объект. As the output from the example shows, person1a and person1b are equal because they reference the same object. person1a Однако и person2 не равны, хотя они имеют одинаковое значение. However, person1a and person2 are not equal, although they have the same value.

Если текущий экземпляр является типом значения, Equals(Object) метод проверяет равенство значений. If the current instance is a value type, the Equals(Object) method tests for value equality. Равенство значений означает следующее: Value equality means the following:

Два объекта имеют один и тот же тип. The two objects are of the same type. Как показано в следующем примере, Byte объект со значением 12 не Int32 равен объекту со значением 12, поскольку два объекта имеют разные типы времени выполнения. As the following example shows, a Byte object that has a value of 12 does not equal an Int32 object that has a value of 12, because the two objects have different run-time types.

Илон Маск рекомендует:  Как сделать цикличным проигрывание midi файла

Значения открытого и закрытого полей двух объектов равны. The values of the public and private fields of the two objects are equal. В следующем примере проверяется равенство значений. The following example tests for value equality. Он Person определяет структуру, которая является типом значения, и Person вызывает конструктор класса для создания экземпляров двух новых Person объектов person1 и, имеющих одно и person2 то же значение. It defines a Person structure, which is a value type, and calls the Person class constructor to instantiate two new Person objects, person1 and person2 , which have the same value. Как видно из выходных данных примера, две объектные переменные ссылаются на разные объекты person1 и person2 равны, так как они имеют одинаковое значение для закрытого personName поля. As the output from the example shows, although the two object variables refer to different objects, person1 and person2 are equal because they have the same value for the private personName field.

Поскольку класс является базовым классом для всех типов в .NET Framework Object.Equals(Object) , метод предоставляет сравнение на равенство по умолчанию для всех остальных типов. Object Because the Object class is the base class for all types in the .NET Framework, the Object.Equals(Object) method provides the default equality comparison for all other types. Однако типы часто переопределяют Equals метод, чтобы реализовать равенство значений. However, types often override the Equals method to implement value equality. Дополнительные сведения см. в примечаниях для вызывающих объектов и примечаний для разделов наследников. For more information, see the Notes for Callers and Notes for Inheritors sections.

Примечания для Среда выполнения Windows Windows Runtime Notes for the Среда выполнения Windows Windows Runtime

При вызове Equals(Object) перегрузки метода для класса Среда выполнения Windows Windows Runtime в он предоставляет поведение по умолчанию для классов, которые не переопределяются Equals(Object). When you call the Equals(Object) method overload on a >Среда выполнения Windows Windows Runtime , it provides the default behavior for classes that don’t override Equals(Object). Это является частью поддержки, предоставляемой .NET Framework для Среда выполнения Windows Windows Runtime (см. раздел поддержка .NET Framework для приложений Магазина Windows и среда выполнения Windows). This is part of the support that the .NET Framework prov >Среда выполнения Windows Windows Runtime (see .NET Framework Support for Windows Store Apps and Windows Runtime). Классы в Среда выполнения Windows Windows Runtime классе не наследуют Object Equals(Object) и в настоящее время не реализуют метод. >Среда выполнения Windows Windows Runtime don’t inherit Object, and currently don’t implement an Equals(Object) method. Однако ToStringони выглядят как методы, Equals(Object)и GetHashCode при их использовании в коде C# или Visual Basic, а .NET Framework предоставляет поведение по умолчанию для этих методов. However, they appear to have ToString, Equals(Object), and GetHashCode methods when you use them in your C# or Visual Basic code, and the .NET Framework provides the default behavior for these methods.

Среда выполнения Windows Windows Runtime классы, написанные на C# языке или Visual Basic могут переопределять Equals(Object) перегрузку метода. classes that are written in C# or Visual Basic can override the Equals(Object) method overload.

Примечания для вызывающих объектов Notes for Callers

Производные классы часто переопределяют Object.Equals(Object) метод для реализации равенства значений. Derived classes frequently override the Object.Equals(Object) method to implement value equality. Кроме того, типы часто предоставляют дополнительный строго типизированную перегрузку для Equals метода, обычно IEquatable реализуя интерфейс. In addition, types also frequently provide an additional strongly typed overload to the Equals method, typically by implementing the IEquatable interface. При вызове Equals метода для проверки на равенство следует знать, переопределяются Object.Equals ли текущий экземпляр и понимаете, как разрешается определенный Equals вызов метода. When you call the Equals method to test for equality, you should know whether the current instance overrides Object.Equals and understand how a particular call to an Equals method is resolved. В противном случае вы можете выполнить проверку на равенство, отличное от предполагаемого, и метод может вернуть непредвиденное значение. Otherwise, you may be performing a test for equality that is different from what you intended, and the method may return an unexpected value.

Ниже приведен пример. The following example provides an illustration. Он создает три StringBuilder объекта с одинаковыми строками, а затем выполняет четыре Equals вызова методов. It instantiates three StringBuilder objects with identical strings, and then makes four calls to Equals methods. Первый вызов метода возвращает true , а остальные три возвращают. false The first method call returns true , and the remaining three return false .

В первом случае вызывается перегруженный метод StringBuilder.Equals(StringBuilder) строгой типизации, который проверяет равенство значений. In the first case, the strongly typed StringBuilder.Equals(StringBuilder) method overload, which tests for value equality, is called. Так как строки, назначенные двум StringBuilder объектам, равны, метод возвращает. true Because the strings assigned to the two StringBuilder objects are equal, the method returns true . Однако не переопределяет Object.Equals(Object). StringBuilder However, StringBuilder does not override Object.Equals(Object). В StringBuilder связи с этим при приведении объекта Objectк StringBuilder типу, когда экземпляр присваивается переменной типа Object, и когда Object.Equals(Object, Object) методу передается два StringBuilder объекта, по умолчанию используется Object.Equals(Object)вызывается метод. Because of this, when the StringBuilder object is cast to an Object, when a StringBuilder instance is assigned to a variable of type Object, and when the Object.Equals(Object, Object) method is passed two StringBuilder objects, the default Object.Equals(Object) method is called. Поскольку StringBuilder является ссылочным типом, это эквивалентно передаче двух StringBuilder объектов в ReferenceEquals метод. Because StringBuilder is a reference type, this is equivalent to passing the two StringBuilder objects to the ReferenceEquals method. Хотя все три StringBuilder объекта содержат одинаковые строки, они ссылаются на три различных объекта. Although all three StringBuilder objects contain identical strings, they refer to three distinct objects. В результате эти три вызова метода возвращают false . As a result, these three method calls return false .

Можно сравнить текущий объект с другим объектом для равенства ссылок, вызвав ReferenceEquals метод. You can compare the current object to another object for reference equality by calling the ReferenceEquals method. В Visual Basic также можно использовать is ключевое слово (например, If Me Is otherObject Then . ). In Visual Basic, you can also use the is keyword (for example, If Me Is otherObject Then . ).

Примечания для наследников Notes for Inheritors

При определении собственного типа этот тип наследует функциональность, определенную Equals методом базового типа. When you define your own type, that type inherits the functionality defined by the Equals method of its base type. В следующей таблице приведена реализация Equals метода по умолчанию для основных категорий типов в .NET Framework. The following table lists the default implementation of the Equals method for the major categories of types in the .NET Framework.

Категория типа Type category Равенство, определенное Equality defined by Комментарии Comments
Класс, производный непосредственно отObject Class derived directly from Object Object.Equals(Object) Равенство ссылок; эквивалентно вызову Object.ReferenceEquals. Reference equality; equivalent to calling Object.ReferenceEquals.
Структура Structure ValueType.Equals Равенство значений; прямое побайтовое сравнение или Сравнение полей по полям с помощью отражения. Value equality; either direct byte-by-byte comparison or field-by-field comparison using reflection.
Перечисление Enumeration Enum.Equals Значения должны иметь одинаковый тип перечисления и одно и то же базовое значение. Values must have the same enumeration type and the same underlying value.
делегат Delegate MulticastDelegate.Equals Делегаты должны иметь одинаковый тип с одинаковыми списками вызовов. Delegates must have the same type with identical invocation lists.
Интерфейс Interface Object.Equals(Object) Равенство ссылок. Reference equality.

Для типа значения следует всегда переопределять Equals, поскольку тесты на равенство, основанные на отражении, имеют низкую производительность. For a value type, you should always override Equals, because tests for equality that rely on reflection offer poor performance. Можно также переопределить реализацию Equals по умолчанию для ссылочных типов, чтобы проверить равенство значений, а не равенство ссылок и определить точное значение равенства значений. You can also override the default implementation of Equals for reference types to test for value equality instead of reference equality and to define the precise meaning of value equality. Такие реализации Equals возвращают true , если два объекта имеют одинаковое значение, даже если они не являются одним и тем же экземпляром. Such implementations of Equals return true if the two objects have the same value, even if they are not the same instance. Разработчик типа принимает решение, что составляет значение объекта, но обычно это некоторые или все данные, хранящиеся в переменных экземпляра объекта. The type’s implementer decides what constitutes an object’s value, but it is typically some or all the data stored in the instance variables of the object. Например, значение String объекта основано на символах строки String.Equals(Object) . метод переопределяет Object.Equals(Object) метод, возвращаемый true для любых двух экземпляров строк, содержащих одинаковые символы в том же порядке. For example, the value of a String object is based on the characters of the string; the String.Equals(Object) method overrides the Object.Equals(Object) method to return true for any two string instances that contain the same characters in the same order.

В следующем примере показано, как переопределить Object.Equals(Object) метод для проверки на равенство значений. The following example shows how to override the Object.Equals(Object) method to test for value equality. Он переопределяет Equals метод Person для класса. It overrides the Equals method for the Person class. Если Person он принял реализацию равенства базового класса, два Person объекта будут равны, только если они ссылались на один объект. If Person accepted its base class implementation of equality, two Person objects would be equal only if they referenced a single object. Однако в этом случае два Person объекта равны, если они имеют одинаковое значение Person.Id для свойства. However, in this case, two Person objects are equal if they have the same value for the Person.Id property.

Помимо переопределения Equals, можно IEquatable реализовать интерфейс, чтобы обеспечить строго типизированный тест на равенство. In addition to overriding Equals, you can implement the IEquatable interface to provide a strongly typed test for equality.

Следующие инструкции должны быть истинными для всех реализаций Equals(Object) метода. The following statements must be true for all implementations of the Equals(Object) method. В x списке, y , и z представляют ссылки на объекты, которые не равны null. In the list, x , y , and z represent object references that are not null.

x.Equals(y) возвращает то же значение, что и y.Equals(x) . x.Equals(y) returns the same value as y.Equals(x) .

x.Equals(y) Возвращает true , x если и y имеют NaN значение. x.Equals(y) returns true if both x and y are NaN .

Если (x.Equals(y) && y.Equals(z)) возвращает true , возвращается x.Equals(z) значение . true If (x.Equals(y) && y.Equals(z)) returns true , then x.Equals(z) returns true .

Последовательные вызовы x.Equals(y) возвращают одно и то же значение до тех пор, пока объекты y , x на которые ссылаются и, не изменяются. Successive calls to x.Equals(y) return the same value as long as the objects referenced by x and y are not modified.

x.Equals(null) возвращает false . x.Equals(null) returns false .

Реализации не должны вызывать исключения. они всегда должны возвращать значение. Equals Implementations of Equals must not throw exceptions; they should always return a value. obj Например, если имеет значение null , Equals метод должен возвращать false , а не создавать ArgumentNullExceptionисключение. For example, if obj is null , the Equals method should return false instead of throwing an ArgumentNullException.

При переопределении Equals(Object)выполните следующие рекомендации. Follow these guidelines when overriding Equals(Object):

Типы, реализующие IComparable , Equals(Object)должны переопределяться. Types that implement IComparable must override Equals(Object).

Типы, переопределяющие Equals(Object) , GetHashCodeтакже должны переопределяться; в противном случае хэш-таблицы могут работать неправильно. Types that override Equals(Object) must also override GetHashCode; otherwise, hash tables might not work correctly.

Рекомендуется реализовать IEquatable интерфейс для поддержки строго типизированных тестов на равенство. You should consider implementing the IEquatable interface to support strongly typed tests for equality. Ваша IEquatable .Equals реализация должна возвращать результаты, которые Equalsсоответствуют. Your IEquatable .Equals implementation should return results that are consistent with Equals.

Если ваш язык программирования поддерживает перегрузку операторов и вы передаете оператор равенства для заданного типа, необходимо также переопределить Equals(Object) метод, чтобы он возвращал тот же результат, что и оператор равенства. If your programming language supports operator overloading and you overload the equality operator for a given type, you must also override the Equals(Object) method to return the same result as the equality operator. Это позволяет гарантировать, что код библиотеки классов, Equals используемый ( ArrayList например, Hashtableи), ведет себя таким образом, который согласуется с тем, как код приложения использует оператор равенства. This helps ensure that class library code that uses Equals (such as ArrayList and Hashtable) behaves in a manner that is consistent with the way the equality operator is used by application code.

Рекомендации по ссылочным типам Guidelines for Reference Types

Следующие рекомендации применяются для переопределения Equals(Object) ссылочного типа. The following guidelines apply to overriding Equals(Object) for a reference type:

Рассмотрите возможность Equals переопределения, если семантика типа основана на том, что тип представляет некоторые значения. Consider overriding Equals if the semantics of the type are based on the fact that the type represents some value(s).

Большинство ссылочных типов не должны перегружать оператор равенства, даже если они Equalsпереопределяют. Most reference types must not overload the equality operator, even if they override Equals. Однако при реализации ссылочного типа, который должен иметь семантику значений, например тип комплексного числа, необходимо переопределить оператор равенства. However, if you are implementing a reference type that is intended to have value semantics, such as a complex number type, you must override the equality operator.

Не следует переопределять Equals для изменяемого ссылочного типа. You should not override Equals on a mutable reference type. Это обусловлено тем, Equals что переопределение требует также GetHashCode переопределения метода, как описано в предыдущем разделе. This is because overriding Equals requires that you also override the GetHashCode method, as discussed in the previous section. Это означает, что хэш-код экземпляра изменяемого ссылочного типа может измениться в течение своего времени существования, что может привести к потере объекта в хэш-таблице. This means that the hash code of an instance of a mutable reference type can change during its lifetime, which can cause the object to be lost in a hash table.

Рекомендации по типам значений Guidelines for Value Types

Ниже приведены рекомендации по переопределению Equals(Object) для типа значения. The following guidelines apply to overriding Equals(Object) for a value type:

При определении типа значения, включающего одно или несколько полей, значения которых являются ссылочными типами, следует переопределить Equals(Object). If you are defining a value type that includes one or more fields whose values are reference types, you should override Equals(Object). Реализация, предоставляемая ValueType функцией, выполняет побайтовое сравнение для типов значений, поля которых являются типами значений, но использует отражение для выполнения сравнения по полям типов значений, поля которых включают ссылочные типы. Equals(Object) The Equals(Object) implementation provided by ValueType performs a byte-by-byte comparison for value types whose fields are all value types, but it uses reflection to perform a field-by-field comparison of value types whose fields include reference types.

Если вы переопределяете Equals и язык разработки поддерживает перегрузку операторов, необходимо перегрузить оператор равенства. If you override Equals and your development language supports operator overloading, you must overload the equality operator.

Необходимо реализовать IEquatable интерфейс. You should implement the IEquatable interface. Вызов строго типизированного IEquatable .Equals метода позволяет избежать obj упаковки-преобразования аргумента. Calling the strongly typed IEquatable .Equals method avoids boxing the obj argument.

Дополнительно

Equals(Object, Object)

Определяет, считаются ли равными указанные экземпляры объектов. Determines whether the specified object instances are considered equal.

Параметры

Первый из сравниваемых объектов. The first object to compare.

Второй из сравниваемых объектов. The second object to compare.

Возвраты

true , если указанные объекты равны; в противном случае — false . true if the objects are cons >false . Если оба параметра objA и objB имеют значение NULL, метод возвращает значение true . If both objA and objB are null, the method returns true .

Примеры

В следующем примере показан Equals(Object, Object) метод и его сравнение ReferenceEquals с методом. The following example illustrates the Equals(Object, Object) method and compares it with the ReferenceEquals method.

Комментарии

Статический Equals(Object, Object) метод указывает, равны ли два объекта objA , objB и. The static Equals(Object, Object) method indicates whether two objects, objA and objB , are equal. Он также позволяет тестировать объекты, значение которых равно null , для проверки на равенство. It also enables you to test objects whose value is null for equality. Он сравнивает objA и objB для равенства следующим образом: It compares objA and objB for equality as follows:

Он определяет, представляют ли два объекта одну и ту же ссылку на объект. It determines whether the two objects represent the same object reference. В противном случае метод возвращает true значение. If they do, the method returns true . Этот тест эквивалентен вызову ReferenceEquals метода. This test is equivalent to calling the ReferenceEquals method. Кроме того, если оба objA значения objB и имеют значение NULL, метод true возвращает. In addition, if both objA and objB are null, the method returns true .

Он определяет, objB является objA ли либо значением NULL. It determines whether either objA or objB is null. Если это так, возвращается false значение. If so, it returns false .

Как правильно: Object.ReferenceEquals или Оператор ==?

Как правильно сравнить два объекта, чтобы определить являются ли экземпляры объектов одним и тем же экземпляром или нет?
Что правильно/лучше использовать: метод Object.ReferenceEquals

ВНИМАНИЕ: не путайте Equals c ReferenceEquals

2 ответа 2

Мне кажется, здесь более важна не техническая сторона вопроса, а читабельность кода.

Если у вас есть два объекта a и b , и вы сравниваете их через == , может быть вызван не operator == (object, object) , а перегруженный оператор сравнения. Это значит, что семантика == шире, чем простое сравнение ссылок.

Если ваша цель — распознать именно один и тот же экземпляр, я бы посоветовал использовать именно ReferenceEquals , т. к. при этом вы прямо «говорите» то, что хотите. Преимущество в компактности кода у == , на мой взгляд, даёт недостаточный выигрыш по сравнению в преимуществе в понятности кода. Да и для правильности сравнения нужно приведение типа к object , которое тоже не добавляет краткости.

С другой стороны, если вам нужно установить не равенство ссылок, а логическую тождественность объектов, для этого более правильным может оказаться использование (возможно перегруженного) оператора == . Поэтому используйте то, что вам нужно. Универсального совета нет, каждый из методов имеет своё применение.

Ещё одна техническая деталь — в обобщённых (generic-) методах на текущий момент (C# 6) невозможно сообщить компилятору, что у типа есть оператор == . Поэтому сравнение через == в generic-методе может дать не такой же результат, как в обычном методе.

Разбираемся с hashCode() и equals()

Я недавно начал заниматься программированием, и в этой области для меня много нового. Данная статья рассчитана на начинающих java-программистов, и, надеюсь, поможет в освоении излюбленной темы для собеседований “ hashCode и equals ”.
Хочу сразу предостеречь, что я не являюсь экспертом в данной теме и могу что-то не так понимать, поэтому, если вы нашли ошибку или неточность — свяжитесь со мной.

Что такое хеш-код?

Если очень просто, то хеш-код — это число. На самом деле просто, не так ли? Если более точно, то это битовая строка фиксированной длины, полученная из массива произвольной длины (википедия).

Пример №1
Выполним следующий код:

В результате выполнения программы в консоль выведется целое 10-ти значное число. Это число и есть наша битовая строка фиксированной длины. В java она представлена в виде числа примитивного типа int , который равен 4-м байтам, и может помещать числа от -2 147 483 648 до 2 147 483 647. На данном этапе важно понимать, что хеш-код это число, у которого есть свой предел, который для java ограничен примитивным целочисленным типом int.

Вторая часть объяснения гласит:

полученная из массива произвольной длины.

Под массивом произвольной длины мы будем понимать объект. В 1 примере в качестве массива произвольной длины у нас выступает объект типа Object .

В итоге, в терминах Java, хеш-код — это целочисленный результат работы метода, которому в качестве входного параметра передан объект.

Этот метод реализован таким образом, что для одного и того-же входного объекта, хеш-код всегда будет одинаковым. Следует понимать, что множество возможных хеш-кодов ограничено примитивным типом int , а множество объектов ограничено только нашей фантазией. Отсюда следует утверждение: “Множество объектов мощнее множества хеш-кодов”. Из-за этого ограничения, вполне возможна ситуация, что хеш-коды разных объектов могут совпасть.

Здесь главное понять, что:

  • Если хеш-коды разные, то и входные объекты гарантированно разные.
  • Если хеш-коды равны, то входные объекты не всегда равны.

Ситуация, когда у разных объектов одинаковые хеш-коды называется — коллизией. Вероятность возникновения коллизии зависит от используемого алгоритма генерации хеш-кода.

Подведём итог:

Сперва, что-бы избежать путаницы, определимся с терминологией. Одинаковые объекты — это объекты одного класса с одинаковым содержимым полей.

  1. для одного и того-же объекта, хеш-код всегда будет одинаковым;
  2. если объекты одинаковые, то и хеш-коды одинаковые (но не наоборот, см. правило 3).
  3. если хеш-коды равны, то входные объекты не всегда равны (коллизия);
  4. если хеш-коды разные, то и объекты гарантированно разные;

Понятие эквивалентности. Метод equals()

Начнем с того, что в java, каждый вызов оператора new порождает новый объект в памяти. Для иллюстрации создадим какой-нибудь класс, пускай он будет называться “BlackBox”.

Пример №2
Выполним следующий код:

Создадим класс для демонстрации BlackBox .

Во втором примере, в памяти создастся два объекта.

Но, как вы уже обратили внимание, содержимое этих объектов одинаково, то есть эквивалентно. Для проверки эквивалентности в классе Object существует метод equals() , который сравнивает содержимое объектов и выводит значение типа boolean true , если содержимое эквивалентно, и false — если нет.

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

Я написал “должно быть”, потому что если вы выполните предыдущий пример, то на самом деле результатом выполнения всех операций будет false . Для пояснения причин, заглянем в исходные коды класса Object .

Класс Object

Как известно, все java-классы наследуются от класса Object . В этом классе уже определены методы hashCode() и equals() .
Определяя свой класс, вы автоматически наследуете все методы класса Object . И в ситуации, когда в вашем классе не переопределены ( @overriding ) hashCode() и equals() , то используется их реализация из Object .

Рассмотрим исходный код метода equals() в классе Object .

При сравнение объектов, операция “ == ” вернет true лишь в одном случае — когда ссылки указывают на один и тот-же объект. В данном случае не учитывается содержимое полей.

Выполнив приведённый ниже код, equals вернет true .

Теперь понято, почему Object.equals() работает не так как нужно, ведь он сравнивает ссылки, а не содержимое объектов.
Далее на очереди hashCode() , который тоже работает не так как полагается.

Заглянем в исходный код метода hashCode() в классе Object :

Вот собственно и вся реализация. Ключевое слово native означает, что реализация данного метода выполнена на другом языке, например на C, C++ или ассемблере. Конкретный native int hashCode() реализован на C++, вот исходники — http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/tip/src/share/vm/runtime/synchronizer.cpp функция get_next_hash .

При вычислении хэш-кода для объектов класса Object по умолчанию используется Park-Miller RNG алгоритм. В основу работы данного алгоритма положен генератор случайных чисел. Это означает, что при каждом запуске программы у объекта будет разный хэш-код.

Получается, что используя реализацию метода hashCode() от класса Object , мы при каждом создании объекта класса new BlackBox() , будем получать разные хеш-коды. Мало того, перезапуская программу, мы будем получать абсолютно разные значения, поскольку это просто случайное число.

Но, как мы помним, должно выполняться правило: “если у двух объектов одного и того же класса содержимое одинаковое, то и хеш-коды должны быть одинаковые ”. Поэтому, при создании пользовательского класса, принято переопределять методы hashCode() и equals() таким образом, что бы учитывались поля объекта.
Это можно сделать вручную либо воспользовавшись средствами генерации исходного кода в IDE. Например, в Eclipse это SourceGenerate hashCode() and equals().

В итоге, класс BlackBox приобретает вид:

Теперь методы hashCode() и equals() работают корректно и учитывают содержимое полей объекта:

Кому интересно переопределение в ручную, можно почитать Effective Java — Joshua Bloch, chapter 3, item 8,9.

Подробная инструкция для начинающих по EQUAL

Проект представляет собой мульти платформу с встроенной дефляционной системой.

Цель EQUAL – упрощение работы экосистемы посредством различных программных продуктов и сервисов.

Они, в свою очередь, подпитываются за счет инвестиций или посредством стимулирования через токены EQUAL на базе ERC-20.

Этот мультиплатформенный токен разработан для того, чтобы объединить цифровые сервисы.

Он может использоваться в многочисленных приложениях вместо того, чтобы работать только с одной платформой или приложением.

Содержание:

Зачем создавался токен EQUAL

Команда проекта внимательно изучила современный мир криптовалют и огромное количество токенов.

Особое внимание было уделено тенденции тому, что многие разработчики проводят ICO и собирают деньги только в тех коинах, которые будут использоваться исключительно в их приложении.

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

В результате, страдают не только инвесторы, но и весь рынок оказывается в состоянии раскола.

В отличие от подобных случаев, мультиплатформенные токены вроде EQL имеют массу преимуществ.

Их цена может расти так как они используются не в одном проекте, а во многих.

В EQUAL вовремя осознали такое положение дел и то, что насыщенный ICO рынок представляет существенный недостаток для всей индустрии.

С одной стороны, инвесторы теряют свои капиталовложения, с другой стороны, далеко не все проекты получают развитие.

Какова основная цель проекта EQUAL

Команда видит применение монеты в различных проектах и приложениях.

Эта цель напрямую связана с планируемым предложением.

Компании смогут воспользоваться преимуществами предложения монет в случае, если они примут монету и будут использовать ее в своих приложениях в форме вознаграждения или расчета.

Что нужно знать пользователям о самодефляционной природе проекта EQUAL

В рамках проекта предусмотрена комиссия за транзакцию в размере одного процента от сделки, но не более 250EQL (EQUAL) для поддержания устойчивого развития проекта.

Комиссия никоим образом не является поощрением для какой-то из сторон.

Средства, полученный в рамках платежа за транзакцию, уничтожаются.

Что такое EQL

Это токен, лежащий в основе экосистемы товаров и услуг, построенной командой и сообществом EQL, а также сторонними разработчиками.

В этом проекте использованы преимущества сети Ethereum (особенно возможность подключения децентрализованных приложений и работы с децентрализованными биржами).

Все это позволяет проекту получить определенные преимущества над конкурентами.

Информация о токенах

Название: EQUAL

Символ: EQL

Тип: ERC-20

Дробная часть: 18 знаков

Первоначальное предложение: 800 миллионов единиц

Адрес контракта: 0x47dd62d4d075dead71d0e00299fc56a2d747bebb

Кошельки EQL

EQUAL является токеном эфириума, поэтому хранить монеты можно практически в любом кошельке Ethereum (от которого у пользователя есть ключи).

В частности, такая возможность доступна в следующих приложениях:

Что необходимо знать про эйрдроп EQL

Команда разработчиков EQUAL решила отказаться от традиционного ICO по многим причинам.

Одной из них является то, что пресейлы ICO обычно благоволят «китам», которые используют высокие транзакционные комиссии для того, чтобы получить криптомонеты. 100% всех размещаемых токенов розданы через эйрдроп.

Этот метод позволяет не только способствовать еще большей децентрализации, но также представляет определенную защиту от «китов» как в процессе создания, так и в период распространения токенов.

40% от общего количества монет были распределены в первом и втором эйрдропах.

Еще 30 процентов были зарезервированы для тех, кто предоставляет сиды (провайдеры серверов). 5% пошло в сообщество и на баунти кампанию. 5% приватным инвесторам. Оставшиеся 20% коинов были предназначены команде EQUAL.

Дорожная карта проекта

В 4-м квартале 2020 года по проекту было реализовано много задумок.

Появился контракт EQUAL на базе токенов ERC-20, был запущен вебсайт, проведен первый раунд эйрдропа для регистрации и распространения монет, появилась первая версия WhiteParer, токены попали в листинг на бирже, прошла регистрация на второй раунд эйрдропа

Итоги

Команда, работающая над EQUAL, отметила один очень серьезный недостаток рынка криптовалют и внедрением токенов EQL пытается его решить. Речь идет о раздробленной структуре этой индустрии.

К тому же, рынок переполнен различными монетами, которые создавались исключительно ради ICO и потом их стоимость либо оставалась на месте, либо вообще снижалась.

EQUAL могла бы стать отличной альтернативой для любых проектов в случае, если бы они согласились использовать EQL вместо создания своих собственных коинов.

С учетом сегодняшнего тренда по этой монете, на начальном этапе с всеобщим внедрением EQUAL могут быть определенные проблемы.

Но в целом, процесс может быть намного упрощен в случае, если люди в индустрии увидят преимущества EQL.

hashcode() и equals() в java, зачем переопределять?

Для начала. Объекты в java могут быть между собой равны, а могут быть эквивалентны

1) равными(через знак ==) могут быть только ссылки, не объекты.
2) эквивалентными называются объекты с одинаковыми значениями полей
но equals != эквивалентность
объясним почему:

hashcode()

hashcode() – метод Object, возвращающий int значение.

В классе Object метод hashCode() определен как public native int hashCode();
исходный код hashCode() написан на другом языке.
Алгоритм генерации хешкода для объекта работает с учаcтием генератора случайных чисел, то есть при каждом выполнении программы хеш-коды объектов будут разными

Однако следует пристально обратить внимание на одно разительное несовершенство функции hashCode():
Если хешкоды объектов не равны, то объекты гарантированно разные. Но, неверно обратное,- если хешкоды объектов равны, то и сами объекты равны.
Ситуация, когда у разных объектов появляются одинаковые хешкоды называется коллизией.
A – хешкод x равен хешкоду y
B – x = y
1) -A -> -B если хешкоды объектов неравны, то объекты неравны
2) -(A -> B) неверно, что если хешкоды равны, то объекты равны
таким образом
(-A -> -B) & (-(A -> B))
(-A \/ B) & (-(A \/ -B))
(-A \/ B) & (-A /\ B)
получаем две истины
-A \/ B
1) хешкоды неравны, и объекты неравны
2) хешкоды равны, объекты неравны
3) хешкоды равны, объекты равны

-A /\ B и есть ситуация коллизии, хешкоды неравны, но объекты равны

equals()

В идеале етод equals() класса Object должен проверять объекты на эквивалентность, исходная же реализация метода equals в классе Object

equals() тупо сравнивает ссылки (ссылки на адреса памяти зарезервированные под объекты), и если они ссылаются на один и тот же объект, возвращает true
equals() не сравнивает значения полей объектов!

Резюмируем:
Итак мы выяснили, что стандартная реализация методов equals() и hashCode() предоставляет из себя весьма скудный и абстрактный инструментарий. Hashcode() выдает нам не всегда уникальный int, а equals по умолчанию, не сравнивает значения полей объекта, а реализован в виде простого ссылочного сравнения.

В чем проблема equals() и hashСode() и зачем их нужно переопределять?

Джошуа Блох в книге “Эффективное программирование” писал так, –
“Переопределяя метод equals() всегда переопределяйте hashCode()”

эээ.. так а в чем проблема? В чем проблема equals() и hashcode() и зачем их нужно переопределять? по умолчанию. инструментарий java не обеспечивает алгоритма сравнения объектов на предмет равенства за исключением сравнения ссылок на адреса разделов памяти, зарезервированных под объекты. Так же, по умолчанию java не гарантирует безупречную(полностью удовлетвлряющую требованиям) работу по идентификации объектов с помощью хешкодов. Иными словами, по умолчанию сравнение объектов в java осуществляется сравнением ссылок на адреса памяти. Но проблема в том, что многие важные инструменты java, такие, как инфраструктура коллекций, переопределяют метод для сравнения equals, используя при этом метод hashcode*. Таким образом, если мы не уделяем внимания объектам(не переопределяем вышеназванные методы), которые могут содержаться в этих типах коллекций, мы подспудно, сами того не осознавая, закладываем в код потенциальную возможность ошибок, связанных с несовершенством этих методов.
Например, мы создаем большую HashMap. Так как хешкод по умолчанию может выдавать одинаковые int-ы, то каждый раз когда мы захотим положить объект в hashmap() ( с помощью put())а его хеш вдруг случайно совпадет с хешем уже существующего в мэпе объекта**(так как ключами в HashMap е являются хеши), то мы не добавим новый объект а просто перетрем значение старого новым значением! Вот так, незатейливо произойдет ошибка.

Переопределяем equals()

Итак, по умолчанию, “равенства” объектов как таковых в java нет. Равными могут быть ссылки. Равенство ссылок означает, что они ссылаются на один и тот же объект.
Однако, правило равенства между объектами одного типа, для того, чтобы их можно было сравнивать, можно написать самому. Что и настоятельно следует делать, переопределяя метод equals()! Вспомним сейчас, что если мы переопределяем equals() то нам также следует переопределить и hashCode, ибо как и было рассказано в предыдущем абзаце, многие важные классы пользуются equals() и hashCode().

I. Самый простой способ реализовать equals() и hashCode() в своем классе, воспользоваться авто-генерацией через IDE. Например, в JIdea это можно сделать с помощью alt + insert.

Также есть ряд требований и рекомендаций к реализации equals() и hashCode()

Реализация equals() должна обладать тремя важными свойствами бинарных отношений
1) рефлексивность: a.equals(a)=true;
2) симметричность: if((a.equals(b)))
3) транзитивность: if((a.equals(b))&&(b.equals(c)))
4) equals() должна возвращать неизменное значение, пока какое-либо из свойств объектов не изменяется.
Пока свойства объектов остаются неизменными, они должны оставаться равны.
4) Повторные вызовы метода equals() должны возвращать одно и тоже значение до тех пор, пока какие-либо значения свойств объекта не будут изменены. То есть, если два объекта равны в Java, то они будут равны пока их свойства остаются неизменными.
5) Необходимо проверять объект на null. В случае, если объект = null, equals() должен возвраoать false, а не выкидывать исключение.
6) не помешает проверка соответствия типа(для этого следует использовать getClass())
7) необходимо привести в соответствие equals() и compareTo() для корректной работы hash-коллекций.***

Резюме

a.hashCode() != b.hashCode() -> !(a.equals(b))
a.hashCode() = b.hashCode() -> ((a.equals(b)) \/ !(a.equals(b)))
Что вносит ущербность в реализацию некоторых коллекций****, основные алгоритмы которых(алгоритмы проверки объектов на предмет равенства) основаны на функциях equals() и hashCode().
Посему в случае, если объекты, планируется содержать в коллекциях, методы которых основаны на данных алгоритмах, рекомендуется переопределять эти методы и приводить их в соответствие бизнес-логике программы

Примечания

**механизм put() класса HashMap несколько сложнее, HashMap содержит массив объектов Enrty, связанный список
***Распространенные ошибки при переопределении equals в Java
****В первую очередь, это коллекции HashSet и HashMap

HashMap и HashSet. Что это на самом деле?

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

Шаг 0. Введение

В практике, мы редко оперируем одним элементом, так как большинство задач нужно решать комплексно. Именно по этому, мы всегда берем какое-то множество объектов чтобы оперировать ими. Но вот только вопрос? Что именно и когда стоит выбирать? Есть много реализаций коллекций, есть массивы. Почему стоит выбрать одно, а не другое? Думаю это стоит знать. Тем более, это один из самых популярных вопросов на собеседовании.

Шаг 1. Что такое хэш-код?

Хэш-код – это целое число, которое является уникальным идентификатором содержимого объекта. От сюда вывод – в каждого объекта, с разными данными, свое уникальное число, с помощью которого мы можем судить о равенстве или неравенстве. В яве, за вычисление этого кода отвечает метод hashCode(), который переопределенный в наследниках Object. Для наших классов мы также должны переопределить его.

Есть несколько правил по переопределению данного метода:

1. Это не должна быть константа. Иначе все будет равным, даже если это не так.

2. Метод генерации должен быть хорошо продуман, иначе могут часто попадаться ситуации коллизии.

3. В генерации желательно использовать именно те поля, которые идентифицируют объект, его уникальность.

Пример того как это все выглядит:

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

1 + 2 = 1 + 2 – равенство верно.

Но что будет если у нас такие объекты:

Здесь поменялся только порядок значений для второго объекта. Эти объекты уже не могут быть равны, но…

1 + 2 = 2 + 1 – равенство осталось верно.

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

Можем сделать вывод:

Для одного и того ж объекта хэш-код всегда один(если не изменять вычисляемые поля)

Если хэш-коды равны, то это не значит что и объекты равны.

Если хэш-коды не равны, то значит и объекты не могут быть равны.

Рассмотрим теперь это на примере. Создадим 2 класса, переопределим вычисление хэш-кода и докажем наши выводы.

И методы main где мы сделаем простую проверку вышесказанного.

Шаг 2. Что тогда такое equals()?

Метод equals() является методом класса Object, и предоставляет возможность объектам определять их соответствие(эквивалентность) с другими. Только что, мы видели что эквивалентность мы определяли с помощью хэш-кода. Здесь подход похож, но не зависит от вычислений числа.

Мы просто сравниваем значимые атрибуты для определения равенства наших объектов. Запомните: изначально, в классе Object идет сравнивание по ссылке, что значит без переопределения данного метода, все ваши объекты будут считаться разными, если только их ссылки не указывают на один и тот же объект.

Используем для примера предыдущий класс и реализуем проверку эквивалентности.

Как вы заметили, эти два понятия тесно связаны и указывают на равенство объектов. Теперь, разобравшись с этим, перейдом непосредственно к коллекциям.

Шаг 3. Организация работы HashMap

– это число, как мы говорили выше.

– коллекция которая состоит с пар “ключ”-“значение”.

HashMap – внутри состоит с так званых корзин и списка элементов, на которые ссылаются корзины.

Корзины – массив
Элементы – связной список. (это рассмотрим дальше)

Добавление

Когда приходит новый элемент, хэш-код ключа определяет корзину, для элемента. В корзине идет проверка, есть ли у нее элементы. Если нету, то корзина получает ссылку нового элемента, если есть, то происходит прохождение по списку элементов и сравнивание элементов в списке. Проверяется равенство hashcode. Так как мы не можем однозначно судить на счет эквивалентности, зная о случаях коллизии, проводится еще сравнивание ключей методом equals.

Если оба равны: идет перезапись

Если не равен equals: добавляется элемент в список

По этому:
1. Если у нас плохой алгоритм расчета хэш-кода, то мы получим обычный связной список и потеряем все преимущества данной структуры. (Добавление, поиск и удаление элементов выполняется за константное время)

2. Важно переопределять метод hashCode & equals для корректной работы.

Получение

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

Предостережение!

Не используйте в качестве ключа массивы. Их хэш код зависит от ссылки. Если даже будете использовать массив с такими ж данными, чтобы получить свое значение, ссылка будет другая и вы не получите свой объект.

Шаг 4. Организация работы HashSet

Почему мы сразу рассмотрели HashMap? Это поможет с пониманием работы следующей коллекции. Здесь все происходит также, единственное отличие здесь в том, что ключом является сам объект.

Предостережение!
Будьте аккуратны в работе с объектом. Если вы поменяете вычисляемые поля объекта, то вы можете навеки потерять его в коллекции.

Вопросы 69-78 (класс Object и его методы equals, hashCode, toString)

«Как связан любой пользовательский класс с классом Object?»
«Расскажите про каждый из методов класса Object.»
«Что такое метод equals(). Чем он отличается от операции ==.»
«Если вы хотите переопределить equals(), какие условия должны удовлетворяться для переопределенного метода?»
«Если equals() переопределен, есть ли какие-либо другие методы, которые следует переопределить?»
«В чем особенность работы методов hashCode и equals? Каким образом реализованы методы hashCode и equals в классе Object? Какие правила и соглашения существуют для реализации этих методов? Когда они применяются?»
«Какой метод возвращает строковое представление объекта?»
«Что будет, если переопределить equals не переопределяя hashCode? Какие могут возникнуть проблемы?»
«Есть ли какие-либо рекомендации о том, какие поля следует использовать при подсчете hashCode?»
«Как вы думаете, будут ли какие-то проблемы, если у объекта, который используется в качестве ключа в hashMap изменится поле, которое участвует в определении hashCode?»

1. В Java есть специальный суперкласс Object и все классы являются его подклассами (это не требуется указывать явно). Поэтому ссылочная переменная класса Object может ссылаться на объект любого другого класса.

1.1. Так как массивы являются тоже классами, то переменная класса Object может ссылаться и на любой массив.

2. У класса есть несколько важных методов:

скрытый текст protected native Object clone() throws CloneNotSupportedException — создаёт новый объект, не отличающий от клонируемого;
public boolean equals(Object obj) — определяет, равен ли один объект другому;
protected void finalize() throws Throwable — вызывается сборщиком мусора, когда он определил, что ссылок на объект больше нет;
public final native Class getClass() — получает класс объекта во время выполнения;
public native int hashCode() — возвращает хеш-код, связанный с вызывающим объектом;
public final native void notify() — возобновляет выполнение одного потока, который ожидает вызывающего объекта;
public final native void notifyAll() — возобновляет выполнение всех потоков, которые ожидают вызывающего объекта;
public String toString() — возвращает строковое представление объекта;
public final void wait() throws InterruptedException — приводит данный поток в ожидание, пока другой поток не вызовет notify() или notifyAll() методы для этого объекта.;
public final native void wait(long timeout) throws InterruptedException —приводит данный поток в ожидание, пока другой поток не вызовет notify() или notifyAll() для этого метода, или пока не истечет указанный промежуток времени.
public final void wait(long timeout, int nanos) throws InterruptedException — приводит данный поток в ожидание, пока другой поток не вызовет notify() или notifyAll() для этого метода, или пока не истечет указанный промежуток времени.

3. Хеш-код — это целочисленный результат работы метода, которому в качестве входного параметра передан объект. Этот метод реализован таким образом, что для одного и того-же входного объекта, хеш-код всегда будет одинаковым. Следует понимать, что множество возможных хеш-кодов ограничено примитивным типом int, а множество объектов ограничено только нашей фантазией. Отсюда следует утверждение: “Множество объектов мощнее множества хеш-кодов”. Из-за этого ограничения, вполне возможна ситуация, что хеш-коды разных объектов могут совпасть.

3.1. Ситуация, когда у разных объектов одинаковые хеш-коды называется коллизией. Вероятность возникновения коллизии зависит от используемого алгоритма генерации хеш-кода.

3.2. У любого объекта имется хеш-код, определяемый по умолчанию, который вычисляется по адресу памяти, занимаемой объектом.

3.2.1. А, например, для вычисления хеш-кода в классе String применяется следующий алгоритм:

Equals, GetHashCode и Operators переопределяют вызов не в реализации IEquatable

Я пытаюсь реализовать IEqueatable, поэтому я мог бы использовать. За исключением запросов LINQ для пользовательского типа.

Код настраиваемого типа выглядит следующим образом:

Я добавил добавить throw new NotImplementedException(); в методе Equals, но он никогда не вызван.

РЕДАКТИРОВАТЬ

Здесь код, который вызывает метод Except:

Где и powerset и subset являются массивами Case .

Прежде чем вы попытаетесь сделать что-то с вашими запросами linq, я бы рекомендовал играть с чем-то более простым. IE

С этим испытанием на месте, вот причины, по которым я могу думать, почему вы не попали в это исключение:

  1. у вас есть 2 метода Equals , и вы исключили исключение только из 1 из них.
  2. Нет двух объектов, которые вы сравнили, имеют один и тот же Id . Если результат GetHashCode отличается, он может даже не попытаться сравнить значения.
  3. Исключение было поймано

Мне было бы интересно узнать, пытались ли вы поймать ловушку в обеих перегрузках для Equals . единственное, что выскочит из вашего кода, — это то, что у вас есть дублирующие реализации для проверки равенства. В идеале вы делаете это только в одном месте.

Вот пример реализации. вы бы заменили EntityBase на Case .

Если вы звоните только за исключением:

Никакой список не возвращается, чтобы выполнить сравнение, необходимое для перечисления результатов Except, например, foreach:

Затем вызывается методы GetHashCode и Equals.

EDIT: этот код содержит только два списка:

Этот код печатает «2» в консоли

Equals вызывают только при необходимости. Все методы LINQ, работающие над реализациями IEquatable сначала используют (и сохраняют) хэш-коды объектов, которые они обрабатывают. Эти методы вызывают только Equals если два объекта имеют один и тот же хеш-код.

В ваших данных нет случая с идентичными Id , поэтому никогда не нужно вызывать Equals .

Это легко продемонстрировать на примере. Если у вас есть три списка:

Затем следующий оператор (с некоторыми инструкциями трассировки в Equals и GetHashCode , а последний просто возвращает Id ).

Java / Отличия equals() от ==

Автор: elvisjagger ← к списку ← →

Метод equals() обозначает отношение эквивалентности объектов. Эквивалентным называется отношение, которое является симметричным, транзитивным и рефлексивным. Рефлексивность: для любого ненулевого x, x.equals(x) вернет true;
Транзитивность: для любого ненулевого x, y и z, если x.equals(y) и y.equals(z) вернет true, тогда и x.equals(z) вернет true;
Симметричность: для любого ненулевого x и y, x.equals(y) должно вернуть true, тогда и только тогда, когда y.equals(x) вернет true.
Также для любого ненулевого x, x.equals(null) должно вернуть false.
Отличия equals() от операции == в классе Object нет. Это видно, если взглянуть исходный код метода equals класса Object:

Однако, нужно не забывать, что, если объект ни на что не ссылается(null), то вызов метода equals этого объекта приведет к NullPointerException. Также нужно помнить, что при сравнении объектов оба они могут быть null и операция obj1 == obj2 в данном случае будет true, а вызов equals приведет к исключению NullPointerException.
Как мы видим, при помощи операции == сравниваются ссылки на объекты. Но мы можем переопределять метод equals, тем самым задавая логику сравнения двух объектов. Например, рассмотрим сравнение двух одинаковых чисел, созданных при помощи класса Integer: Если взглянуть внутрь метода equals класса Integer, то мы увидим: Понятно, что тут уже нет сравнения ссылок, а сравниваются int значения.

Если Вам понравился вопрос, проголосуйте за него

Илон Маск рекомендует:  Что такое код pg_cancel_query
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL