20

If I run the below code then the output is 2 which means that the set contains 2 elements. However I think that set should contain 1 since both the objects are equal based on hashcode() value as well as .equals() method. Seems like some obvious mistake in my understanding ?

package HELLO;

import java.util.HashSet;
import java.util.Set;

public class Test {

    public static void main(String[] args) throws Exception {
        Set<Alpha> s = new HashSet<Alpha>();
        Alpha a1 = new Alpha();
        Alpha a2 = new Alpha();
        s.add(a1);
        s.add(a2);
        System.out.println(s.size());
    }
}   

class Alpha {
    int a = 10;

    public int hashcode() {
        return a;
    }

    public boolean equals(Object obj) {
        return (obj instanceof Alpha && ((Alpha) obj).a == this.a);
    }

    public String toString() {
        return "Alpha : " + a;
    }
}
m5khan
  • 2,667
  • 1
  • 27
  • 37
snow_leopard
  • 1,466
  • 2
  • 20
  • 36

3 Answers3

36

Your hashcode method does not override the Object class's hashCode method and thus your equals method breaks contract since it doesn't agree with the hashCode results, and you can have objects that are "equal" but have different hashCodes.

Remember: You should always use the @Override annotation when overriding methods as this will help you catch this and similar errors.

@Override  // ** don't forget this annotation
public int hashCode() { // *** note capitalization of the "C"
  return a;
}

Also, you will want to improve your code formatting, especially when posting code here for our review. We will be able to better understand your code and help you if it conforms to standards (that's why standards exist). So try to keep your indentations consistent with all code lines that are in the same block indented at the same level, and you will want to be sure that base level code, including imports, outer class declarations and its end curly brace, is flush left:

import java.util.HashSet;
import java.util.Set;

public class Test {

   public static void main(String[] args) throws Exception {
      Set<Alpha> s = new HashSet<Alpha>();
      Alpha a1 = new Alpha();
      Alpha a2 = new Alpha();
      s.add(a1);
      s.add(a2);
      System.out.println(s.size());
   }
}

class Alpha {
   int a = 10;

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

   public String toString() {
      return "Alpha : " + a;
   }

   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (obj == null)
         return false;
      if (getClass() != obj.getClass())
         return false;
      Alpha other = (Alpha) obj;
      if (a != other.a)
         return false;
      return true;
   }
}

For a beautiful review on this, please read: Overriding equals and hashCode in Java

Community
  • 1
  • 1
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • Thanks! Would never forget to use @Override anymore :) – snow_leopard May 09 '13 at 16:33
  • @snow_leopard: it's a great habit to get in to. Good luck! – Hovercraft Full Of Eels May 09 '13 at 16:38
  • Besides "@Override" I also had to add a line in the equals function, otherwise the set was not able to detect duplicates and always contained an object with the same content multiple times: if(this.hashCode() == msg.hashCode()) return true; – Sven Jung Jan 21 '15 at 08:32
  • 1
    @sven: I actually strongly recommend against your line of code since it is the exact opposite of what the equals and hashCode contract stipulates. Your need of that line suggests that there may be something else wrong with your equals method. – Hovercraft Full Of Eels Jan 21 '15 at 16:45
  • 1
    @hoverkraft: You are right, I had an error in equals() what returned false in a wrong case., so that multiple entries occured. Bad idea to check for hash in equals(). – Sven Jung Jan 22 '15 at 15:40
4

The @Overrides annotation is to override the method with the same name in the super class".

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

@Override
public boolean equals(Object obj) {
    return (obj instanceof Alpha && ((Alpha) obj).a == this.a);

}

@Override
public String toString() {
    return "Alpha : " + a;
}
Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
4

your method hashcode should be named hashCode (capital letter "C").

If you plan on overriding methods you should use the @Override annotation.

If you had used that annotation, you'd have noticed the problem earlier as the code wouldn't have compiled.

Mena
  • 47,782
  • 11
  • 87
  • 106