What is HashMap? When do you use HashMap?
Start with common facts about HashMap like HashMap accept null while Hashtable doesn't, HashMap is not synchronized, HashMap is fast and it stores key and value pairs in form of Map.Entry. Below are some points you can mention:
How HashMap works in Java or How does get () method of HashMap works ?
The answer to this question is HashMap works on principle of hashing, we have put(key, value) and get(key) method for storing and retrieving Objects from HashMap. When we pass Key and Value object to put() method on Java HashMap, HashMap implementation calls hashCode method on Key object and applies returned hashcode into its own hashing function to find a bucket location for storing Entry object, main point to mention is that HashMap in Java stores both key and value object as Map.Entry in bucket which is essential to understand the retrieving logic.
Now next question is like What will happen if two different objects have same hashcode ?
Here you need to remind yourself about equals() and hashCode() contract that two unequal object in Java can have same hash code. So don't say its not possible or something like that. Now the answer to this question is "Since hashcode is same, bucket location would be same and collision will occur in HashMap, Since HashMap use LinkedList to store object, this entry (object of Map.Entry comprise key and value ) will be stored in LinkedList.
You have answered that two keys can have same hashCode but how will you retrieve Value object if two Keys will have same hashcode?
The normal answer to this question is we will call get() method and then HashMap uses Key Object's hashcode to find out bucket location and retrieves Value object. But here case is different we have same bucket location for two different objects, so you can explain about traversal in LinkedList until we find the value object. Here we already know map stores Key as well as Value in Map.Entry, so after finding bucket location, we will call key.equals() method to identify correct node in LinkedList starting from head of LinkedList until key.equals() method return true and return associated value object for that key in Java HashMap. Also, point out here that using immutable, final object with proper equals() and hashcode() implementation would act as perfect Java HashMap keys and improve performance of Java HashMap by reducing collision. Immutability also allows caching there hashcode of different keys which makes overall retrieval process very fast and suggest that String and various wrapper classes e.g. Integer very good keys in Java HashMap.
Below is sample image to show how Map.Entry saved in LinkedList.
Here for all there objects HashCode is same and it is an example of collision. Now consider a situation where we want to get Object whoes key is K2. So first bucket location will be decided by Key K2. Now we travers LinkedList on this location, first call K2.equeals(K1) it will return false so it ensures that this is not the Object we are looking for. Next we will travers to next node of LinkedList and will call K2.equals(K2), it will return true. This ensures that this is the Object which is associated with this key K2 and we will return this value of this node.
Loadfactor and Rehashing in HashMap:
The default initial capacity (16) and the default load factor (0.75). You can change these values by using any of the below methods while initializing hashmap:
HashMap(int initialCapacity)
Constructs an empty HashMap with the specified initial capacity and the default load factor (0.75).
HashMap(int initialCapacity, float loadFactor)
Constructs an empty HashMap with the specified initial capacity and load factor.
Last but not least as we know hashmap is not synchronized is there any potential race condition exists while resizing HashMap in Java, if two thread at the same time found that now HashMap needs resizing and they both try to resizing.
Answer to this question is Yes, in the process of resizing of HashMap in Java , the element in bucket which is stored in linked list get reversed in order during there migration to new bucket because Java HashMap doesn't append the new element at tail instead it append new element at head to avoid tail traversing. If race condition happens then you will end up with an infinite loop.
Points to remember:
Since equals() and hashCode() are used to store and retrieve values, how does it work in case of null key?
There are two separate method for that putForNullKey(V value) and getForNullKey(). Later is offloaded version of get() to look up null keys. Null keys always map to index 0. This null case is split out into separate methods for the sake of performance in the two most commonly used operations (get and put), but incorporated with conditionals in others. In short, equals() and hashcode() method are not used in case of null keys in HashMap.
Below is code snippet to retrieve Null key from HashMap
private V getForNullKey() {
if (size == 0) {
return null;
}
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
Start with common facts about HashMap like HashMap accept null while Hashtable doesn't, HashMap is not synchronized, HashMap is fast and it stores key and value pairs in form of Map.Entry. Below are some points you can mention:
- HashMap is implemented as a hash table, and there is no ordering on keys or values.
- LinkedHashMap preserves the insertion order so when we need order Map we use LinkedHashMap.
- Hashtable is synchronized, in contrast to HashMap but it is slow.
How HashMap works in Java or How does get () method of HashMap works ?
The answer to this question is HashMap works on principle of hashing, we have put(key, value) and get(key) method for storing and retrieving Objects from HashMap. When we pass Key and Value object to put() method on Java HashMap, HashMap implementation calls hashCode method on Key object and applies returned hashcode into its own hashing function to find a bucket location for storing Entry object, main point to mention is that HashMap in Java stores both key and value object as Map.Entry in bucket which is essential to understand the retrieving logic.
Now next question is like What will happen if two different objects have same hashcode ?
Here you need to remind yourself about equals() and hashCode() contract that two unequal object in Java can have same hash code. So don't say its not possible or something like that. Now the answer to this question is "Since hashcode is same, bucket location would be same and collision will occur in HashMap, Since HashMap use LinkedList to store object, this entry (object of Map.Entry comprise key and value ) will be stored in LinkedList.
You have answered that two keys can have same hashCode but how will you retrieve Value object if two Keys will have same hashcode?
The normal answer to this question is we will call get() method and then HashMap uses Key Object's hashcode to find out bucket location and retrieves Value object. But here case is different we have same bucket location for two different objects, so you can explain about traversal in LinkedList until we find the value object. Here we already know map stores Key as well as Value in Map.Entry, so after finding bucket location, we will call key.equals() method to identify correct node in LinkedList starting from head of LinkedList until key.equals() method return true and return associated value object for that key in Java HashMap. Also, point out here that using immutable, final object with proper equals() and hashcode() implementation would act as perfect Java HashMap keys and improve performance of Java HashMap by reducing collision. Immutability also allows caching there hashcode of different keys which makes overall retrieval process very fast and suggest that String and various wrapper classes e.g. Integer very good keys in Java HashMap.
Below is sample image to show how Map.Entry saved in LinkedList.
Here for all there objects HashCode is same and it is an example of collision. Now consider a situation where we want to get Object whoes key is K2. So first bucket location will be decided by Key K2. Now we travers LinkedList on this location, first call K2.equeals(K1) it will return false so it ensures that this is not the Object we are looking for. Next we will travers to next node of LinkedList and will call K2.equals(K2), it will return true. This ensures that this is the Object which is associated with this key K2 and we will return this value of this node.
Loadfactor and Rehashing in HashMap:
The default initial capacity (16) and the default load factor (0.75). You can change these values by using any of the below methods while initializing hashmap:
HashMap(int initialCapacity)
Constructs an empty HashMap with the specified initial capacity and the default load factor (0.75).
HashMap(int initialCapacity, float loadFactor)
Constructs an empty HashMap with the specified initial capacity and load factor.
If the size of the Map exceeds a given threshold defined by load-factor e.g. if load factor is .75 it will act to re-size the map once it filled 75%. Similar to other collection classes like ArrayList, Java HashMap re-size itself by creating a new bucket array of size twice of previous size of HashMap , and then start putting every old element into that new bucket array. This process is called rehashing because it also applies hash function to find new bucket location.
Last but not least as we know hashmap is not synchronized is there any potential race condition exists while resizing HashMap in Java, if two thread at the same time found that now HashMap needs resizing and they both try to resizing.
Answer to this question is Yes, in the process of resizing of HashMap in Java , the element in bucket which is stored in linked list get reversed in order during there migration to new bucket because Java HashMap doesn't append the new element at tail instead it append new element at head to avoid tail traversing. If race condition happens then you will end up with an infinite loop.
Points to remember:
- String, Integer and other wrapper classes are natural candidates of HashMap key, and String is most frequently used key as well because String is immutable and final,and overrides equals and hashcode() method.
- If you want to use any Object as key in Java HashMap you need to make sure it follows equals and hashCode contract and its hashCode should not vary once the object is inserted into Map. If custom object is Immutable than this will be already taken care because you can not change it once created.
- In HashMap bucket is allocated by using modulus (%) function. The bucket location will be basically the output of (key % size of HashMap), default HashMap size is 16 so by default bucket location will be decided by output of (key%16).
Since equals() and hashCode() are used to store and retrieve values, how does it work in case of null key?
There are two separate method for that putForNullKey(V value) and getForNullKey(). Later is offloaded version of get() to look up null keys. Null keys always map to index 0. This null case is split out into separate methods for the sake of performance in the two most commonly used operations (get and put), but incorporated with conditionals in others. In short, equals() and hashcode() method are not used in case of null keys in HashMap.
Below is code snippet to retrieve Null key from HashMap
private V getForNullKey() {
if (size == 0) {
return null;
}
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
So that was all I have to share with you guys on this thread.