2

I always thought hat HashMap is identifying its keys by using hasCode and equals. But this code still does not give me the value back. What am I missing?

import java.util.HashMap;
import java.util.Map;

/**
 * Created by kic on 25.04.15.
 */
public class TypePair {
    private final Class a;
    private final Class b;

    public TypePair(Class a, Class b) {
        this.a = a;
        this.b = b;
    }

    public TypePair(Object a, Object b) {
        this.a = a.getClass();
        this.b = b.getClass();
    }

    public boolean isPair (Object a, Object b) {
        return this.a.isAssignableFrom(a.getClass()) && this.b.isAssignableFrom(b.getClass());
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof TypePair) {
            return a.isAssignableFrom(((TypePair) obj).a) && b.isAssignableFrom(((TypePair) obj).b);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return 1;
    }

    public static void main(String[] args) {
        TypePair a = new TypePair(Number.class, String.class);
        TypePair b = new TypePair(12, "hello");

        Map<TypePair, Boolean> test = new HashMap<>();
        test.put(a, true);

        System.out.println(a.hashCode() == b.hashCode());
        System.out.println(a.equals(b));
        System.out.println("und? " + test.get(a));
        System.out.println("und? " + test.get(b));
    }
}

This code prints:

true
true
und? true
und? null
2
  • 6
    Check what b.equals(a) returns. Commented Apr 25, 2015 at 13:41
  • @resueman damn it you are right! Commented Apr 25, 2015 at 13:42

1 Answer 1

5

Your implementation of equals() is violating the contract (it is not symmetric), that's why it does not work correctly.

You need to use something like:

@Override
public boolean equals(Object obj) {
    if (obj instanceof TypePair) {
        TypePair objTypePair = (TypePair) obj;
        return a            .isAssignableFrom(objTypePair.a) && b            .isAssignableFrom(objTypePair.b) ||
               objTypePair.a.isAssignableFrom(a)             && objTypePair.b.isAssignableFrom(b);
    } else {
        return false;
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

you are right: return (a.isAssignableFrom(((TypePair) obj).a) && b.isAssignableFrom(((TypePair) obj).b)) || obj.equals(this); and it works.
Or just this.a == that.a && this.b == that.b.
@Radiodef I think you did not get the point that I want to match super classes so this.a is never that.a
Oops, I didn't see the ||. Then this answer is actually still a wrong implementation of equals because it's not transitive. You can't actually do what you're trying to do.
See e.g. ideone.com/c1hAjy It still doesn't work. equals: "It is transitive: if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true."
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.