2

I want to create a map which has a certain class as a key. The problem I ran into is that since this class contains pointers, this address is used when hashing if I use a HashMap (See my code below). How can I get it to compare the actual values rather than the address, or is there some other container that I can use that'll achieve the same result?

import java.util.*;
public class Main {
    public static void main(String args[]) {
        class Foo {
            public Foo(String a) {s = a;}
            public String s;
        }

        HashMap<Foo,Integer> a = new HashMap<Foo,Integer>();
        a.put(new Foo("test"), 1);
        System.out.println(a.get(new Foo("test")));
    }
}

This outputs null

howardh
  • 614
  • 2
  • 7
  • 15
  • Your question title is not correct. You're looking at using objects as keys, not classes. If you were using classes as keys, that would look like this: `HashMap a;` Also, dasblinkenlight is correct. You need to define equals and hashcode in the class of the objects you want to use for the map key. – Bill May 28 '12 at 01:42

2 Answers2

9

In order to use instances of a class as keys in a HashMap you need to override its hashCode and equals methods. Once you do, everything should work fine.

class Foo {
    public Foo(String a) {s = a;}
    public String s;
    int hashCode() {return s.hashCode();}
    boolean equals(Object other) {
        if (other == this) return true;
        if (!(other instanceof Foo)) return false;
        return ((Foo)other).s.equals(s);
    }
}
Sergey Kalinichenko
  • 675,664
  • 71
  • 998
  • 1,399
  • Does the hash code of each instance of the object have to be unique? The example I gave above is just a minimal example and usually, I'd have other member variables too, so any advice on making this hashing function? – howardh May 28 '12 at 01:46
  • 3
    @howardh `hashCode` does not need to be unique (in fact it cannot be unique most of the time), but it has to obey the [hashcode/equals contract](http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Object.html#hashCode()) of Java - it has to be the same every time you call it on the same object, and has to be the same for equal objects, but not necessarily the other way around (i.e. objects with the same hash code do not have to be equal). – Sergey Kalinichenko May 28 '12 at 01:50
  • Please be careful with mutability of the "key" (field `s` in this case). At least, the "key" must be immutable to use the associative containers properly. Details: [Are mutable hashmap keys a dangerous practice?](http://stackoverflow.com/questions/7842049/are-mutable-hashmap-keys-a-dangerous-practice). – Sergey Brunov Oct 05 '14 at 22:35
1

Notice that you're not parameterizing the Map with a class as a key, but with instances of the class Foo. If you were using a class as a type parameter for the map, it'd look like this:

Map<Class<Foo>,Integer> map;

Understanding that the above is not the case for your code, if you need the map to work with instances of Foo:

Map<Foo,Integer> map;

... Then you need to make sure that Foo overrides both equals() and hashCode() for everything to work fine. Here's a nice article explaining how you should override both methods.

Community
  • 1
  • 1
Óscar López
  • 215,818
  • 33
  • 288
  • 367