Every class in Java always inherits from class Object, which is the first class in the inheritance hierarchy. It is in this class that two methods are defined that, by virtue of inheritance, every object in Javacan call:
...
public native int hashCode();
...
public boolean equals(Object obj) {
return (this == obj);
}
...
Regarding the first method , the goal of hashCodeis to return an integer that 'identifies' the object when it is saved in a data structure known as HashMap (or others like Hashtable , HashSet ), whose goal is to store a set of values (in the form similar to a ArrayListor an array). These structures, except for some differences, persist the data in the following way:
When wanting to save an object in this structure, the method is called hashCode(), as I mentioned, it returns an integer, which the structure will use to decide in which ' bucket ' it will save this data. Now, if I want to retrieve the object I saved, I call the method hashCodeagain, thus determining which drawer to retrieve the object from (like when I save key/value data, it calls the method hashCodeof the key to get the corresponding value). The goal of saving data in this way and calling the method is to achieve constant time storage and retrieval (which isn't always the case, but it's close). Whether this does not happen depends, almost always, on the value returned by the hashCode() method for each object.
Suppose we save 3 objects in this structure and the method hashCodeof the 3 returns 0, this means that the 3 objects will be saved in drawer 0. If I want to recover them, it will happen that I must now go through the objects that I have saved in this drawer to determine which one do I want? Therefore, the hashCode() method of these objects is not useful, since what is achieved is that when the elements are saved, they are uniformly dispersed throughout the structure (the least number of empty drawers remain and there are no drawers where many more items are stored than others).
Regarding the implementation hashCodeof the class method Object, the identifier nativeindicates that it is the responsibility of the compiler to determine how it will carry out this task. In all the implementations I've reviewed, it natively returns a numeric representation of the 'memory address' at which the object is located. This seems like a good default strategy, but it has a big problem: there are many more memory addresses than 'number of buckets' so the structure solves the problem (again, this is also implementation dependent) by assigning it bucket number hashcode()%MAX_LENGTHwhere MAX_LENGTH is the maximum size of the array. So, the greater the number of elements to store, the greater the probability that there will be drawers in the structure that have an excess of elements.
For this reason, if you need to store elements in this type of structure, Javait is advisable to override this method. Some IDEs like Eclipse or Netbeans allow you to generate a method hashCodefrom the class properties, and that is enough to solve this problem.
Regarding the second method , equals(), the default implementation of the class Objectis clear: it compares references between objects. So not overriding it when defining a class is a very bad idea, because there would be no difference between calling equals()and using the operator ==. The documentation is clear in pointing out the features this method should have when comparing:
Reflexivity: If I compare an object with itself, it should return true.
Symmetry: If I compare an object A with an object B and it returns true, then the comparison of object B with object A must also return true.
Transitivity: if I compare an object A with an object B and it returns trueand I compare object B with another object C and it returns true, when comparing object A with object C it should return true.
Consistency: if the objects A and B are not modified, successive calls to the method must return the same value.
Now, as you'll notice, method equals()doesn't call method hashCode(), so why override method hashCode()when method is overridden equals()? the easiest answer is because the documentation suggests so: if two objects are equal, they must have the same value returned by hashCode(). Despite being a suggestion, again the operation on these structures shows why it is necessary: if two objects have the same hashCode, both objects will be stored in the same bucket, the structure now uses the method equals()
inside that bucket to determine which corresponds to the one requested, and for that it depends on you having overridden the method, otherwise it does not guarantee a correct result.
In summary:
If you override the method, equals()it is recommended to also override the method hashCode()to preserve the contract between the two methods: two identical objects must return the same hash value. The method equals()does not call the method hashCode()to determine the equality of two objects.
It is recommended, if not mandatory, to override the method equals()because the default implementation is not very helpful.
If two objects are not equal, it is not necessary to override the method hashCode(), even two different objects can return equal hash values.
If you need to save the objects in the structures noted above ( HashMapand the like) it is absolutely essential that you override the method hashCode(), otherwise you will get unexpected or undesirable results when performing save, query or delete operations on the data.
No. What the method does equalsis evaluate if one object is equal to another. If a class does not override the method equals, then the result of using equalswill be the same as using the operator ==between objects. The method hashCodeis not associated with the use of method evaluation equals.
The method hashCodeis used to obtain a hash code that would be like an identifier of the object. This hash is used in some collections like HashSet, HashMap, LinkedHashSet, LinkedHashMap, ConcurrentHashMap, among others. What the hash does is help the container to locate the element in the collection structure and helps to search if an object with said hash already exists, this to ensure an O(1) search time (assuming that the number of collisions It is low).
An example of how the algorithm works , where the and HashSet#addmethods are used . (It's an idea, the actual implementation is more complex and uses more mechanisms to ensure whether to increase or decrease the size of the internal structure, but that's beside the point)hashCodeequals
//es pseudocódigo, no es código Java
//se utiliza una matriz para guardar los elementos
Object[][] conjunto = ...
metodo agregar (elemento)
int hash = nuevo.hashCode();
si (hash < conjunto.length)
//pueden haber varios elementos con el mismo hash
//por ello se utiliza una matriz
//el hash ayuda a
Object[] elementosConMismoHash = arreglo[hash];
var encontrado = falso;
para cada Object actual en elementosConMismoHash
si actual.equals(nuevo) entonces
encontrado = verdadero;
romper para;
fin si
fin para
si no fue encontrado entonces
agregar nuevo en elementosConMismoHash
fin si
fin si
fin metodo
As you can see, the hashCodeis used as an identifier, but there can be multiple elements with the same result of hashCode. This does not guarantee that the objects are the same by using equals.
Due to the efficiency of the method equals(), the hashcode of the two objects is usually compared at the beginning, so that if they are not equal, it is returned immediately false, avoiding the rest of the comparisons.
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MiClase other = (MiClase) obj;
if (this.hashCode() != other.hashCode())
return false;
// Otras comparaciones
}
Every class in Java always inherits from class
Object
, which is the first class in the inheritance hierarchy. It is in this class that two methods are defined that, by virtue of inheritance, every object inJava
can call:Regarding the first method , the goal of
hashCode
is to return an integer that 'identifies' the object when it is saved in a data structure known as HashMap (or others like Hashtable , HashSet ), whose goal is to store a set of values (in the form similar to aArrayList
or an array). These structures, except for some differences, persist the data in the following way:When wanting to save an object in this structure, the method is called
hashCode()
, as I mentioned, it returns an integer, which the structure will use to decide in which ' bucket ' it will save this data. Now, if I want to retrieve the object I saved, I call the methodhashCode
again, thus determining which drawer to retrieve the object from (like when I save key/value data, it calls the methodhashCode
of the key to get the corresponding value). The goal of saving data in this way and calling the method is to achieve constant time storage and retrieval (which isn't always the case, but it's close). Whether this does not happen depends, almost always, on the value returned by the hashCode() method for each object.Suppose we save 3 objects in this structure and the method
hashCode
of the 3 returns 0, this means that the 3 objects will be saved in drawer 0. If I want to recover them, it will happen that I must now go through the objects that I have saved in this drawer to determine which one do I want? Therefore, the hashCode() method of these objects is not useful, since what is achieved is that when the elements are saved, they are uniformly dispersed throughout the structure (the least number of empty drawers remain and there are no drawers where many more items are stored than others).Regarding the implementation
hashCode
of the class methodObject
, the identifiernative
indicates that it is the responsibility of the compiler to determine how it will carry out this task. In all the implementations I've reviewed, it natively returns a numeric representation of the 'memory address' at which the object is located. This seems like a good default strategy, but it has a big problem: there are many more memory addresses than 'number of buckets' so the structure solves the problem (again, this is also implementation dependent) by assigning it bucket numberhashcode()%MAX_LENGTH
where MAX_LENGTH is the maximum size of the array. So, the greater the number of elements to store, the greater the probability that there will be drawers in the structure that have an excess of elements.For this reason, if you need to store elements in this type of structure,
Java
it is advisable to override this method. Some IDEs like Eclipse or Netbeans allow you to generate a methodhashCode
from the class properties, and that is enough to solve this problem.Regarding the second method ,
equals()
, the default implementation of the classObject
is clear: it compares references between objects. So not overriding it when defining a class is a very bad idea, because there would be no difference between callingequals()
and using the operator==
. The documentation is clear in pointing out the features this method should have when comparing:true
.true
, then the comparison of object B with object A must also returntrue
.true
and I compare object B with another object C and it returnstrue
, when comparing object A with object C it should returntrue
.Now, as you'll notice, method
equals()
doesn't call methodhashCode()
, so why override methodhashCode()
when method is overriddenequals()
? the easiest answer is because the documentation suggests so: if two objects are equal, they must have the same value returned byhashCode()
. Despite being a suggestion, again the operation on these structures shows why it is necessary: if two objects have the same hashCode, both objects will be stored in the same bucket, the structure now uses the methodequals()
inside that bucket to determine which corresponds to the one requested, and for that it depends on you having overridden the method, otherwise it does not guarantee a correct result.In summary:
equals()
it is recommended to also override the methodhashCode()
to preserve the contract between the two methods: two identical objects must return the same hash value. The methodequals()
does not call the methodhashCode()
to determine the equality of two objects.equals()
because the default implementation is not very helpful.hashCode()
, even two different objects can return equal hash values.HashMap
and the like) it is absolutely essential that you override the methodhashCode()
, otherwise you will get unexpected or undesirable results when performing save, query or delete operations on the data.No. What the method does
equals
is evaluate if one object is equal to another. If a class does not override the methodequals
, then the result of usingequals
will be the same as using the operator==
between objects. The methodhashCode
is not associated with the use of method evaluationequals
.The method
hashCode
is used to obtain a hash code that would be like an identifier of the object. This hash is used in some collections likeHashSet
,HashMap
,LinkedHashSet
,LinkedHashMap
,ConcurrentHashMap
, among others. What the hash does is help the container to locate the element in the collection structure and helps to search if an object with said hash already exists, this to ensure an O(1) search time (assuming that the number of collisions It is low).An example of how the algorithm works , where the and
HashSet#add
methods are used . (It's an idea, the actual implementation is more complex and uses more mechanisms to ensure whether to increase or decrease the size of the internal structure, but that's beside the point)hashCode
equals
As you can see, the
hashCode
is used as an identifier, but there can be multiple elements with the same result ofhashCode
. This does not guarantee that the objects are the same by usingequals
.Due to the efficiency of the method
equals()
, the hashcode of the two objects is usually compared at the beginning, so that if they are not equal, it is returned immediatelyfalse
, avoiding the rest of the comparisons.