0

In android I'm trying to save grids that the user already have pressed.

Code snipping I’m using is:

// private
private HashSet<int[]> PlayerSelectedHashField = new HashSet<int[]>();
private boolean collisionDetected = false;

In a function I’m using

collisionDetected = PlayerSelectedHashField.contains(TmpPos); // -> Fail - not working
{doing something}
PlayerSelectedHashField.add(TmpPos); // int[] TmpPos - TmpPos is x y

The .add function is working as expected, but .contains always return false. Why does it not working - and what can I do instead?

user1564762
  • 745
  • 2
  • 11
  • 18

2 Answers2

3
public boolean contains(Object o) {
    return map.containsKey(o);
}

containsKey:

public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}

getNode:

final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        if ((e = first.next) != null) {
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
}

It will not work since equals of arrays will do a == compare, and it will return true only if they point to the same instance.

Your problem could be fixed without work with Arrays.equals (the way to compare two arrays elements and not reference) (could be problematic (at least, for me.) i prefer an easy way)

Since you save X and Y coordinates, just make a class Point

public class Point {
    public final int X;
    public final int Y;

    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (obj == this) {
            return true;
        }

        if (obj instanceof Point) {
            Point pObj = (Point) obj;
            return pObj.X == X && pObj.Y == Y;
        }

        return false;
    }

    @Override
    public int hashCode()
    {
        int result = X;
        result = 31 * result + Y;
        return result;
    }
}

then use Point class to save X, Y points.

Instead of create your custom point class, you can use the Android Point.

Example

Set<Point> points = new HashSet<Point>();
points.add(new Point(1, 3));
points.add(new Point(1, 4));

System.out.println(points.contains(new Point(1, 3)));
System.out.println(points.contains(new Point(1, 4)));
System.out.println(points.contains(new Point(1, 5)));
Marco Acierno
  • 14,682
  • 8
  • 43
  • 53
  • 2
    Good answer, FYI there already is a [Point](http://developer.android.com/reference/android/graphics/Point.html) class that OP could use. – ashishduh May 22 '14 at 19:28
  • Oh i didn't read Android tag. I will add it thanks @ashishduh – Marco Acierno May 22 '14 at 19:28
  • 1
    quick question: why 31? – njzk2 May 22 '14 at 19:36
  • @njzk2 Because 31 is an odd prime. Effective Java 2nd edition have a great description about it. Here mattb quoted him http://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier – Marco Acierno May 22 '14 at 19:38
  • Fabulous example. It worked fine with but not with int[]. Actually I hade already tried with points but had forget “new Point” inside contains. Thanks. – user1564762 May 22 '14 at 19:58
0

From the HashSet javadocs:

public boolean contains(Object o)

Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)).

So, generally, if you don't know what happens when you call equals on a particular object type, then contains also may not behave as you expect. It is never a bad idea to make a class for a particular object if that object type has conceptual meaning in your program. If you do that, you can override the equals method to make sure it is behaving exactly as you want.

slevin
  • 308
  • 1
  • 8