简体   繁体   中英

Misunderstanding of hash function in java and working of contains on HashSet

I have some doubts when it comes to way of working hashes and HashSet in Java.

We know about following assumption which we should fullfil:

if elements are equals then also their hashes are equals

in other words:

a.equals(b) ---> a.hashCode() == b.hashCode()   

However, we can't say that

a.hashCode() == b.hashCode() --->  a.equals(b)   

The problem is that I did read that contains on HashSet computes hash h , and then searches only in bucket for hash h for element. It doesn't call equals on elements of bucket for h - it calss only hashCode . It means that we contains can return wrong answer in case elements have equals hashed, but equals return false (As I mentioned above it is possible).

While it is true that

a.hashCode() == b.hashCode() doesn't mean that a.equals(b)

When calling contains Method in Java HashSet, the containsKey Method of the backing HashMap is called. This Method checks if the Node of that Object is null, the getNode Function also checks if the key equals the object

final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        if ((e = first.next) != null) {
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}

First, you should understand how hashmap works in java:

  1. HashMap in java stores key and value object, in a bucket, as an object of Entry class which implements nested interface Map.Entry.

  2. When put() method is used to store (Key, Value) pair, HashMap implementation calls hashcode on Key object to calculate a hash that is used to find a bucket where Entry object will be stored. When get() method is used to retrieve value, again key object is used to calculate a hash which is used then to find a bucket where that particular key is stored.

  3. HashMap key object is used for comparison, also using equals() method Map knows how to handlehashing collision (hashing collision means more than one key having the same hash value, thus assigned to the same bucket. In that case objects are stored in a linked list

  4. hashCode method helps in finding the bucket where that key is stored, equals method helps in finding the right key as there may be more than one key-value pair stored in a single bucket.

so now coming to your question when you call

i. if elements are equals then also their hashes are equals ii. a.equals(b) ---> a.hashCode() == b.hashCode() iii. a.hashCode() == b.hashCode() ---> a.equals(b)

Blockquote it's not always true, It's perfectly legal for two unequal objects to have the same hash code. It's used by HashMap as a "first pass filter" so that the map can quickly find possible entries with the specified key. if two unequal objects couldn't have the same hash code, then that would limit you to 2^32 possible objects.

Now coming to HashSet

Blockquote A set is a collection of unique objects, with Java defining uniqueness two objects in HashSet won't be equal

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM