Question

I am trying to create a search algorithm that stores coordinate pairs in a wrapper class called HashSquareSpec. In order to avoid duplicates, and maintain insertion order, I am inserting each HashSquareSpec into a LinkedHashSet. Even though I have overridden the equals() method and hashCode() methods, the LinkedHashSet still accepts two HashSquareSpec objects with the same coordinate pairs.

public static void main(String [] args)
{
    LinkedHashSet<HashSquareSpec> firedShots = new HashLinkedSet<HashSquareSpec>();
    HashSquareSpec a = new HashSquareSpec(1,2);
    HashSquareSpec b = new HashSquareSpec(2,2);
    HashSquareSpec c = new HashSquareSpec(1,2);
    HashSquareSpec d = new HashSquareSpec(3,2);

    firedShots.add(a);
    firedShots.add(b);
    firedShots.add(c);
    firedShots.add(d);
    System.out.println(a.equals((SquareSpec)c));
    Iterator l = firedShots.iterator();
    while(l.hasNext())
    {
        System.out.println(l.next().hashCode());
    }
}

Output:
true
38444474
38474265
38444474
38504056

HashSquare class

public class HashSquareSpec extends SquareSpec 
{
  public HashSquareSpec(int sx, int sy) 
  {
    super(sx,sy);
  }

  public HashSquareSpec(String codeString) 
  {
    super(codeString);
  }

  @Override  
  public int hashCode() 
  {  
    return this.toString().hashCode();  
  }  

  public boolean equals(HashSquareSpec other) 
  {
    if(this.toString().equals(other.toString()))
      return true;
    else
      return false;
  }
}

and the super class of HashSquareSpec

public class SquareSpec {
  public int x;
  public int y;

  public SquareSpec(int sx, int sy) {
      this.x = sx; 
      this.y = sy;
  }

  public SquareSpec(String codeString) {
      this.x = Integer.parseInt(codeString.substring(1,2));
      this.y = Integer.parseInt(codeString.substring(3,4));
  }

  public String toString() {
      return("(" + x + "," + y + ")");
  }

  public boolean equals(SquareSpec other) {
      return (other.x == this.x  && 
              other.y == this.y );
    }
  }

Despite many different hashCode variations and Eclipse equals and hashCode generation, the firedShots data structure keeps accepting duplicates. What is wrong with my code?

Was it helpful?

Solution

You are on the right track, overriding hashcode and equals, except you are incorrectly overriding the equals method from Object in HashSquareSpec (and SquareSpec). The parameter must be an Object. Because it's not overridden, equals from Object is called, which compares object references to see if they're the same object. They aren't, so the "duplicate" is allowed.

Try:

@Override
public boolean equals(Object other) 
{
  if(this.toString().equals(other.toString()))
    return true;
  else
    return false;
}

You should also test if other is null and then ensure that other is the same type.

Include the @Override annotation so that the compiler will complain if the method doesn't actually override anything.

OTHER TIPS

It's still accepting because you are not overriding the equals method. You need to override boolean equals(Object). The problem is that you're defining a new method like boolean equals(SquareSpec).

Here is the method that LinkedHashSet#add(T) eventually invokes:

HashMap#put(K, V):

@Override public V put(K key, V value) {
    if (key == null) {
        return putValueForNullKey(value);
    }

    int hash = secondaryHash(key.hashCode());
    HashMapEntry<K, V>[] tab = table;
    int index = hash & (tab.length - 1);
    for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
        if (e.hash == hash && key.equals(e.key)) {
            preModify(e);
            V oldValue = e.value;
            e.value = value;
            return oldValue;
        }
    }

As you can see, it compares using hashCode and equals(Object).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top