What happens if we override only hashCode () in the class and use it in Set?

This may not be a real-world scenario, but just curious to find out what is happening, the code is below.

I am creating a set of objects of the UsingSet class. According to the concept of hashing in Java, when I first add an object that contains "a", it will create a bucket with hashcode 97 and put the object in it. Again, when he encounters an object with "a", he will call the overridden hashcode method in the UsingSet class, and he will get hashcode 97, and what will happen next?

As I did not override the equals method, the default implementation will return false. So, where will the object with the value β€œa” be stored, in the same bucket where the previous object with hashcode 97 was stored? or will he create a new bucket? Does anyone know how it will be stored inside?

 /* package whatever; // don't place package name! */ import java.util.*; import java.lang.*; import java.io.*; class UsingSet { String value; public UsingSet(String value){ this.value = value; } public String toString() { return value; } public int hashCode() { int hash = value.hashCode(); System.out.println("hashcode called" + hash); return hash; } public static void main(String args[]) { java.util.Set s = new java.util.HashSet(); s.add(new UsingSet("A")); s.add(new UsingSet("b")); s.add(new UsingSet("a")); s.add(new UsingSet("b")); s.add(new UsingSet("a")); s.add(new Integer(1)); s.add(new Integer(1)); System.out.println("s = " + s); } } 

:

 hashcode called65 hashcode called98 hashcode called97 hashcode called98 hashcode called97 s = [1, b, b, A, a, a] 
+2
source share
5 answers

James The big answer is incorrect or, rather, misleading (and partially incorrect). I will explain.

If two objects are equal according to their equals () method, they must also have the same hash code. If two objects have the same hash code, they also should NOT be equal.

Here is the actual wording from the java.util.Object documentation:

  • If two objects are equal in accordance with the equals (Object) method, then calling the hashCode method for each of the two objects should lead to the same integer result.
  • It is not required that if two objects are unequal according to the equals method (java.lang.Object), then calling the hashCode method for each of the two objects must produce different integer results. However, the programmer should be aware that obtaining separate integer results for unequal objects can improve the performance of hash tables.

True, if two objects do not have the same hash, then they are not equal. However, hashing is not a way to verify equality - so it is wildly incorrect to say that it is a faster way to verify equality.

In addition, it is also wildly incorrect to say that the hashCode function is an effective way to do something. All this is implementation related, but the default implementation for hashCode of a string is very inefficient as String gets big. It will perform calculations based on each char String, so if you use large strings as keys, it becomes very inefficient; moreso if you have a large number of buckets.

On the map (HashSet uses HashMap internally), there are buckets, and each bucket has a linked list. Java uses the hashCode () function to find out which bucket it enters (it will actually change the hash, depending on how many buckets exist). Since two objects can share the same hash, it will iterate over the linked list sequentially, checking the equals () method to see if the object is a duplicate. According to java.util.Set documenation:

A collection that does not contain duplicate elements.

So, if its hashCode () leads it to a bucket in which this bucket contains an object where .equals () evaluates to true, then the previous object is overwritten with the new object. You can probably look here for more information: How does Java HashMap process different objects with the same hash code?

Generally speaking, it’s good that if you overwrite the hashCode function, you also overwrite the equals function (if I'm not mistaken, this breaks the contract if you don't want to).

+4
source

HashCode and Equals Methods

  • Only override HashCode, use default values: Only links to the same object will return true. In other words, those objects that you expected to be equal will not be equal by calling the equals method.
  • Just override peers, use the default HashCode: There may be duplicates in the HashMap or HashSet. We are writing the equals method and expect {"abc", "ABC"} be equal. However, when using HashMap, they can be displayed in different codes, so the contains() method will not detect each other.
+3
source

Without looking at your code ...

The whole point of hash codes is to speed up the process of testing two objects for equality. It can be costly to check if two large complex objects are equal, but their hash codes are easy to compare and the hash codes can be precomputed.

Rule: if two objects do not have the same hash code, this means that they are not equal. There is no need to perform an expensive equality test.

So, the answer to the question is in your title: if you define the equals () method, which says that object A is equal to object B, and you define the hashCode () method, which says that object A is not equal to object B (i.e. he says that they have different hash codes), and then you transfer these two objects to some library that takes care of whether they are equal or not (for example, if you put them in the hash table), then the library behavior will be undefined (i.e., probably wrong).


Added information: Wow! I really missed seeing the forest for trees here, thinking about the hashCode () target, not putting it in the HashMap context. If m is a card with N elements, and k is the key; What is the purpose of calling m.get(k) ? Obviously, the goal is to find a card for the record whose key is k.

What if the hash codes and hash cards were not invented? Well, what you could do, assuming the keys are in a natural general order, is to search the TreeMap by comparing the given key for equality with O (log (N)) other keys. In the worst case, when the keys are not in order, you need to compare this key for equality with each key on the map, until you find a match or check all of them. In other words, the complexity of m.get(k) will be O (N).

When m is a HashMap, the complexity of m.get(k) is O (1), can keys be ordered or not.

So, I messed up by saying that hash codes should speed up the process of testing two objects for equality. This really applies to testing an object for equality with a whole set of other objects. That comparing the hash codes doesn't just help a bit; It helps an order of magnitude ...

... If the methods k.hashCode() and k.equals(o) obey the rule: j.hashCode()!=k.hashCode() implies !j.equals(k) .

0
source

Set will behave differently.

Uniqueness will not happen. Because the unique will be achieved using the hashcode and equals methods.
the output will like this s = [A, a, b, 1] instead of the earlier one.

In addition, remove and contains everything does not work.

0
source

You can simply use the hashcode and equals methods as a 2D search, for example: -

Where the Hashcode is the rows and the list of objects is the column. Consider the following class structure.

 public class obj { int Id; String name; public obj(String name,int id) { this.id=id; this.name=name; } } 

now if you create such objects: -

 obj obj1=new obj("Hassu",1); obj obj2=new obj("Hoor",2); obj obj3=new obj("Heniel",3); obj obj4=new obj("Hameed",4); obj obj5=new obj("Hassu",1); 

and you place these objects on the map as follows: -

  HashMap hMap=new HashMap(); 1. hMap.put(obj1,"value1"); 2. hMap.put(obj2,"value2"); 3. hMap.put(obj3,"value3"); 4. hMap.put(obj4,"value4"); 5. hMap.put(obj5,"value5"); 

now, if you have not redefined hashcode and are equal, after you put all the objects up to line 5, if you put obj5 on the map, because by default HashCode you get a different hashCode, so the line (Bucket will be different). Thus, during operation, the memory will be saved as follows.

 |hashcode | Objects |-----------| --------- |000562 | obj1 |000552 | obj2 |000588 | obj3 |000546 | obj4 |000501 | obj5 

Now, if you create the same Like object: - obj obj6 = new obj ("hassu", 1); And if you are looking for this value on map.like

 if(hMap.conaints(obj6)) or hMpa.get(obj 6); 

although the key (obj1) with the same contents is available, you will get false and null respectively. Now, if you override only the equals method. and to execute the same content search key will also get Null, since the HashCode for obj6 is different and you will not find any key in this hash code. Now, if you override only the hashCode method.

You will get the same bucket (HashCode string), but the content cannot be verified, and it will perform a standard check on the Super Object Class. SO here, if you are looking for the key hMap.get (obj6), you will get the correct hash code: - 000562, but since the link for obj1 and obj6 is different, you will get zero.

0
source

Source: https://habr.com/ru/post/1269615/


All Articles