Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restricting the Object Type for the get method in a Java HashMap [duplicate]

Tags:

java

hashmap

I have instantiated my HashMap like this:

Map<String, Integer> myHashMap = new HashMap<String, Integer>();

The datatype of the Key is String, so when I try to insert a new key-value pair in the map keeping the Key as Integer, it throws an error.

myHashMap.put(1L, "value");

That means in the put method they have restricted the datatype of the Key. But while fetching the value from the map using the get method it is not checking for the datatype of the Key. So if I write something like this, it doesn't give a compilation error.

myHashMap.get(1L);

I checked the get method in the Java Map interface and its parameter type is Object, so that's why it is allowing any Object as the put method argument.

V get(Object key)

Is there a way I can restrict the datatype which I pass as an argument in the get method?

The argument that I pass should have the same datatype as the datatype of the Key which I use while instantiating my hashmap.

like image 342
Rito Avatar asked Apr 22 '19 07:04

Rito


People also ask

Does HashMap allow duplicate values in Java?

HashMap stores key, value pairs and it does not allow duplicate keys. If the key is duplicate then the old key is replaced with the new value.

How do you avoid duplicates in maps?

If you have to avoid duplicates you also know we have to use Set from the collections. You can do like Map<set<id>,sObject> newMap = Map<set<id>,sObject>(); Please take it as a general solution which you can modify as per your requirement.

How does get () method of HashMap works if two keys have the same hashCode?

If two keys are the same ( equals() returns true when you compare them), their hashCode() method must return the same number. If keys violate this, then keys that are equal might be stored in different buckets, and the hashmap would not be able to find key-value pairs (because it's going to look in the same bucket).


2 Answers

It is designed that way, since during the get operation only the equals and hashCode is used to determine the object to be returned. The implementation of the get method does not check for the type of the Object used as the key.

In your example you are trying to get the value by passing a long like myHashMap.get(1L);, firstly the hash code of the object Long having the value 1L will be used to determine the bucket from which to look for. Next the equals method of the key is used to find out the exact entry of the map from which to return the value. And in a well-defined equals method there is always a check for the type:

public boolean equals(Object obj) {
    if (obj instanceof Long) { //here type is checked
        return value == ((Long)obj).longValue();
    }
    return false;
}

So if the types are not equal, the equals method returns false and hence get also will return null.

In some cases such as when using List as a key, it may happen that you put an item in the map using an instance of say an ArrayList but you can successfully retrieve the same value with an instance of an LinkedList. As both implement the List interface.

Map<List<String>, String> myHashMap = new HashMap<>();
List<String> arrayList = new ArrayList<>();
List<String> linkedList = new LinkedList<>();
myHashMap.put(arrayList, "foo");
System.out.println(myHashMap.get(linkedList));

The above code will output in the console foo.

Here although the implementations are different but if you examine the equals method of ArrayList, it is only checking if the type is a List:

public boolean equals(Object o) {
        if (o == this) {
            return true;
        }

        if (!(o instanceof List)) { //checking type of super interface
            return false;
        }
        ...
}

The same is true for LinkedList.

like image 86
Fullstack Guy Avatar answered Oct 16 '22 06:10

Fullstack Guy


I think if it is very important in a project that we control type in HashMap, we could extend HashMap and force using this class instead of HashMap like the below code.

We have all HashMap capabilities, and we should just use the getValue method instead of the get method.

import java.util.HashMap;

public class MyHashMap<K,V> extends HashMap<K,V> {

    public V getValue(K key) {
        return super.get(key);
    }
}

Test class:

 public class Test {
     public static void main(String[] args) {
         MyHashMap<String,Integer> map = new MyHashMap();
     }
 }
like image 44
hamid rostami Avatar answered Oct 16 '22 06:10

hamid rostami