Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map with objects as a key

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

like image 469
howardh Avatar asked Aug 09 '26 05:08

howardh


2 Answers

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);
    }
}
like image 101
Sergey Kalinichenko Avatar answered Aug 11 '26 19:08

Sergey Kalinichenko


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.

like image 28
Óscar López Avatar answered Aug 11 '26 20:08

Óscar López