简体   繁体   中英

why doesn't ArrayList as key in HashMap work?

I am trying to use an ArrayList as a key in a HashMap , but if I add values to the list after setting the list as a key, the map won't recognize the list anymore. I have already found a solution for my problem, but it is an ugly way of doing it, here is some example code for the problem:

HashMap<Object,String> hm = new HashMap<Object,String>();

List<String> l = new ArrayList<String>();
hm.put(l, "stuff");
l.add("test");//add item after adding the list to the hashmap

System.out.println(hm.get(l));

this will return the text "null" while

HashMap<Object,String> hm = new HashMap<Object,String>();

List<String> l = new ArrayList<String>();
l.add("test"); //add item before adding the list to the hashmap
hm.put(l, "stuff");

System.out.println(hm.get(l));

works fine and returns "stuff"

Does anyone know why this happens?

Short: because keys must be immutable for hashmaps to work (at least their identity must be immutable) and lists aren't.

Long: when you add a key to a map its hashCode() method is used to determine the bucket the entry is put into. Inside that bucket equals() is used to check whether that key already exists in there. The same is true for lookups.

Now ArrayList does a deep equals() and hashCode() so if you alter the list after using it as key you'll end up in a different bucket or with a different outcome for equals() and the map most likely won't find it.

Edit

hashCode() implementation for AbstractList (which ArrayList extends):

public int hashCode() {
    int hashCode = 1;
    for (E e : this)
        hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
    return hashCode;
}

As you can see: if the list is empty the hash code will be 1 otherwise the hash code will be something else (in your case 31 * "test".hashCode() ). Thus you're likely to end up looking in a different bucket which will fail.

Edit 2

Clarification on "different outcome for equals() ": of course equals() should return true if the list used as a key and the list used for the lookup only contain equal elements in the same order. But if you change that list after using it as a key you might end up in different situations:

  • Although hashCode returns a different value it might get mapped to the same bucket (in the worst case think of only one bucket in the map). In that case you'd end up with two equal keys in the list although they weren't equal before.
  • You might not be aware of changes to the list and thus might not use an equal list for the lookup even if you think you are.

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