简体   繁体   中英

Can we use object as a key in hashmap in Java?

How to use an object as a key in a hashmap. If you use an object as key do you need to override equals and hashcode methods for that object?

A simple thumb rule is to use immutable objects as keys in a HashMap .

because:

If it were mutable, then the hashcode() value or equals() condition might change, and you would never be able to retrieve the key from your HashMap .

More precisely, class fields that are used to compute equals() and hashcode() should be immutable!

Now, suppose you create your own class:

  • To compare two objects of your class you will have to override equals()
  • To use it as a key in any Hash based Data structure you will have to override hashcode() (again, keeping immutability in mind)

Remember that if two objects are equal() , then their hashcode() should be equal as well!

hashCode() -HashMap provides put(key, value) for storing and get(key) method for retrieving Values from HashMap. 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.

equals() - equals() method is used to compare objects for equality. In case of HashMap key object is used for comparison, also using equals() method Map knows how to handle hashing 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, refer figure for more clarity. Where 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.

您可以在HashMap使用任何对象,只要它具有正确定义的hashCodeequals方法——这些绝对是至关重要的,因为散列机制取决于它们。

Yes, you should override equals and hashcode, for the proper functioning of the code otherwise you won't be able to get the value of the key which you have inserted in the map.

eg

map.put(new Object() , "value") ;

when you want to get that value ,

map.get(new Object()) ; // This will always return null

Because with new Object() - new hashcode will be generated and it will not point to the expected bucket number on which value is saved, and if eventually bucket number comes to be same - it won't be able to match hashcode and even equals so it always return NULL .

Answer to your question is yes, objects of custom classes can be used as a key in a HashMap. But in order to retrieve the value object back from the map without failure, there are certain guidelines that need to be followed.

1)Custom class should follow thecontract between hashCode() and equals().

The contract states that:

If two objects are equal according to the equals(Object) method, then calling
the hashCode method on each of the two objects must produce the same integer result.

This can be done by implementing hashcode() and equals() in your custom class.

2) Make custom class immutable.

Hint: use final, remove setters, use deep copy to set fields

Yes, we can use any object as key in a Map in java but we need to override the equals() and hashCode() methods of that object class. Please refer an example below, in which I am storing an object of Pair class as key in a hashMap with value type as string in map. I have overriden the hashCode() and equals() methods of Pair class. So, that different objects of Pair class with same values of Pair(x,y) will be treated as one object only.

import java.util.*;
import java.util.Map.Entry;

class App { // Case-sensitive
    private class Pair {
        private int x, y;

        public Pair(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + x;
            result = prime * result + y;
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Pair other = (Pair) obj;

            if (x != other.x)
                return false;
            if (y != other.y)
                return false;
            return true;
        }

    }

    public static void main(String[] args) {
        App obj = new App();
        obj.show();
    }

    private void show() {
        Map<Pair, String> map = new HashMap<>();
        Pair obj1 = new Pair(10, 20);
        Pair obj2 = new Pair(40, 50);
        Pair obj3 = new Pair(10, 20);
        // We can see that obj1 and obj3 have same values. So, we want to store these
        // objects
        // as one .To achieve
        // that,
        // we have overridden equals() and hashCode() methods of Pair class.

        map.put(obj1, "First");
        map.put(obj2, "Second");
        map.put(obj3, "Third");
        System.out.printf("Size of Map is :%d \n", map.size());

        for (Entry<App.Pair, String> p : map.entrySet()) {
            Pair pair = p.getKey();
            System.out.printf("Map key-value pair is (%d,%d)->%s \n", pair.x, pair.y, p.getValue());
        }
        // output -
        // Size of Map is :2
        // Map key-value pair is (10,20)->Third
        // Map key-value pair is (40,50)->Second
    }

}
package com.java.demo.map;

import java.util.HashMap;

public class TestMutableKey
{
    public static void main(String[] args)
    {
        //Create a HashMap with mutable key
        HashMap<Account, String> map = new HashMap<Account, String>();

        //Create key 1
        Account a1 = new Account(1);
        a1.setHolderName("A_ONE");
        //Create key 2
        Account a2 = new Account(2);
        a2.setHolderName("A_TWO");

        //Put mutable key and value in map
        map.put(a1, a1.getHolderName());
        map.put(a2, a2.getHolderName());

        //Change the keys state so hash map should be calculated again
        a1.setHolderName("Defaulter");
        a2.setHolderName("Bankrupt");

        //Success !! We are able to get back the values
        System.out.println(map.get(a1)); //Prints A_ONE
        System.out.println(map.get(a2)); //Prints A_TWO

        //Try with newly created key with same account number
        Account a3 = new Account(1);
        a3.setHolderName("A_THREE");

        //Success !! We are still able to get back the value for account number 1
        System.out.println(map.get(a3)); //Prints A_ONE
    }
}

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