Can an array be used as a HashMap key?
Solution 1
It will have to be the same object. A HashMap
compares keys using equals()
and two arrays in Java are equal only if they are the same object.
If you want value equality, then write your own container class that wraps a String[]
and provides the appropriate semantics for equals()
and hashCode()
. In this case, it would be best to make the container immutable, as changing the hash code for an object plays havoc with the hash-based container classes.
EDIT
As others have pointed out, List<String>
has the semantics you seem to want for a container object. So you could do something like this:
HashMap<List<String>, String> pathMap;
pathMap.put(
// unmodifiable so key cannot change hash code
Collections.unmodifiableList(Arrays.asList("korey", "docs")),
"/home/korey/docs"
);
// later:
String dir = pathMap.get(Arrays.asList("korey", "docs"));
Solution 2
No, but you can use List<String>
which will work as you expect!
Solution 3
Arrays in Java use Object
's hashCode()
and don't override it (the same thing with equals()
and toString()
). So no, you cannot shouldn't use arrays as a hashmap key.
Solution 4
You cannot use a plain Java Array
as a key in a HashMap
. (Well you can, but it won't work as expected.)
But you could write a wrapper class that has a reference to the Array and that also overrides hashCode()
and equals()
.
Solution 5
Ted Hopp is right it will have to be same object.
For information see this example:
public static void main(String[] args) {
HashMap<String[], String> pathMap;
pathMap = new HashMap<String[], String>();
String[] data = new String[]{"korey", "docs"};
pathMap.put(data, "/home/korey/docs");
String path = pathMap.get(data);
System.out.println(path);
}
When you run the above code, it will print "docs".
Comments
-
Korey Hinton almost 2 years
If a
HashMap
's key is aString[]
array:HashMap<String[], String> pathMap;
Can you access the map by using a newly created
String[]
array, or does it have to be the sameString[]
object?pathMap = new HashMap<>(new String[]{"korey", "docs"}, "/home/korey/docs"); String path = pathMap.get(new String[]{"korey", "docs"});
-
pvorb almost 11 yearsI think it also uses
hashCode()
to determine the hash of an object. -
Lucas almost 11 yearsYou can use them as a key, it will just use whatever Object does for its hashCode... Not what he wants, but nothing stopping you from doing it.
-
Ted Hopp almost 11 years@pvorb - Indeed. And two arrays are unlikely to have the same hash code. However, this is not a requirement for any Java implementation. In any case, two references with the same
hashCode()
are then compared usingequals()
to determine if they are the same key. -
Steve Kuo almost 11 yearsNo need write a new array wrapper class, one already exists -
ArrayList
-
Ted Hopp almost 11 yearsThis works with a caveat. If you're going to use a
List<String>
as a key in a hash-based collection, the list should be unmodifiable. If the hash code for an object changes while the object is being used as a key in a hash-based collection, the collection generally breaks. -
Steve Kuo almost 11 years
List
is an interface, and there no guarantee that an implementation properly overrides equals and hashCode -
pvorb almost 11 years@SteveKuo Yes, indeed. But maybe you want to write your own, since
ArrayList
is mutable and the array underneath can be replaced internally without you noticing it. -
Ted Hopp almost 11 years@SteveKuo - Yes there is. The documentation for
List
requires any implementation to use a specific semantics forequals()
andhashCode()
. The required semantics matches what OP seems to want. -
Ted Hopp almost 11 years@pvorb - One can always use
Collections.unmodifiableList(someList)
to turn aList
into an immutable object. -
Korey Hinton almost 11 years@TedHopp I decided to use your suggestion to make a container class. Thanks!
-
Ted Hopp almost 11 years@KoreyHinton - You're welcome. :) Before doing that, though, check whether
List
does what you need. See my edited answer. -
Korey Hinton almost 11 years@TedHopp Cool I just now saw your edit, thanks for showing a working example!
-
Mark Bennett about 10 yearsThis all sounded very promising, but when I try to do containsKey I get a
ClassCastException: java.util.Collections$UnmodifiableList cannot be cast to java.lang.Comparable
, still researching... -
Ted Hopp about 10 years@MarkBennett - Weird. AFAIK
HashMap.containsKey
does not require keys to implementComparable
. It only relies onhashCode()
andequals()
. Something else must be going on in your code. -
Theodore Murdock over 7 yearsNote that the collection returned by
Collections.unmodifiableList(List)
is not immutable--if the underlying list is later modified, the hashcode of the unmodifiable list wrapping it will change. So the call toCollections.unmodifiableList
protects the keys from modification by, for example, a malicious or misguided consumer iterating the keyset and modifying keys, but if the underlying list used as a key could later change, defensive copying is also necessary. -
Ted Hopp over 7 years@TheodoreMurdock - Good point. The usual idiom for using
Collections.unmodifiableList(List)
is to not keep a reference to the argument (as in my sample code), so this usually isn't a problem. It's only when the argument is separately modifiable (through a separate reference) that things can get messed up. -
Alex almost 7 years@TedHopp: an unmodifiableList is not an immutable one.You still can modify the source list directly.
-
Ted Hopp almost 7 years@Alex - Yes, you are correct. This was pointed out in this comment to my own answer above. See also my response to that comment.
-
Florian F over 5 yearsThe question would be then: Is there a suitable container class that will wrap an array and provide the needed hasCode() and equals()? It looks like a very generic thing.
-
Ted Hopp over 5 years@FlorianF - You mean for an array of mutable objects? I think an identity hash is the only sensible approach in that case. If the hash code for key objects can change dynamically, a hash-based data structure is unsuitable right from the start.
-
Peng over 3 yearsIndeed, the AbstractList class which is the superclass all list implementations inherit from overrides both hashCode() and equals() methods, so that the element-wise comparison, rather than reference comparison, is reflected.
-
Peng over 3 yearsThe problem with this approach is that it cannot deal with hash collision when 2 string[] has the same hashCode under Arrays.hashCode().