Friday, February 14, 2020

HashSet equals method in java

Before to understand, how HashSet work with HashCode & Equals methods. We have to understand about hashcode & equals methods.

Note:- Point to be remember that. As it implements the Set Interface, duplicate values are not allowed.

Method Definition and Default Implementation
equals(Object obj): As we know equal method belong java.lang.Object that indicates that by default — two objects are equal if and only if they are stored in the same memory address. provided by the JDK, based on memory location. by default it check only reference of object.
by default equal method check references like "==". If  not override.

hashcode(): As we know equal method belong java.lang.Object that returns an integer representation of the object memory address. By default, hashcode() method returns a random integer that is unique for each instance.

The Contract Between equals() and hashcode()
1) If two objects are equal according to the equals(Object) method, then hashcode of of two object by the hashcode() method on each of the two objects must be the same integer.
2) if hashcode of two object is same by hashcode() method but object may not equal by calling equals(Object) method.click here to see in more details

Without hashCode and equal method
package hashsetEqualExample;

public class Student {
 private int id;
 private String name;

 public Student(int id, String name) {
  this.name = name;
  this.id = id;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 /*
  * @Override public boolean equals(Object obj) { if (obj == null) return false;
  * if (!(obj instanceof Student)) return false; if (obj == this) return true;
  * return this.getId() == ((Student) obj).getId(); }
  * 
  * @Override public int hashCode() { return id; }
  */
}
package hashsetEqualExample;

import java.util.HashSet;

public class HashcodeEquals {

 public static void main(String[] args) {
  Student student1 = new Student(1, "Amit");
  Student student2 = new Student(1, "Amit");
  System.out.println("student1 hashcode = " + student1.hashCode());
  System.out.println("student2 hashcode = " + student2.hashCode());
  System.out.println("equality check between student1 and student2 = " + student1.equals(student2));

  System.out.println("\n\n#######HashSet Test##### without hashcode & equal method########");
  HashSet<Student> students = new HashSet<Student>();
  students.add(student1);
  students.add(student2);
  System.out.println("HashSet size = " + students.size());
  System.out.println("HashSet contains Amit = " + students.contains(new Student(1, "Amit")));
 }
}
Output:
student1 hashcode = 1829164700
student2 hashcode = 2018699554
equality check between student1 and student2 = false


#######HashSet Test##### without hashcode & equal method########
HashSet size = 2
HashSet contains Amit = false

As in the above example. I have not Override hashCode() and equals() methods so the hashCode of the two object with same value are different and they are not seems to be equal. Hence HashSet consider this as two different object and add into HashSet. And while i try to get new object with same value its return false because this is new object for HashSet.

With hashCode() and without equals() method
package hashsetEqualExample;

public class Student {
 private int id;
 private String name;

 public Student(int id, String name) {
  this.name = name;
  this.id = id;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 /*
  * @Override public boolean equals(Object obj) { if (obj == null) return false;
  * if (!(obj instanceof Student)) return false; if (obj == this) return true;
  * return this.getId() == ((Student) obj).getId(); }
  */

 @Override
 public int hashCode() {
  return id;
 }
}
package hashsetEqualExample;

import java.util.HashSet;

public class HashcodeEquals {

 public static void main(String[] args) {
  Student student1 = new Student(1, "Amit");
  Student student2 = new Student(1, "Amit");
  System.out.println("student1 hashcode = " + student1.hashCode());
  System.out.println("student2 hashcode = " + student2.hashCode());
  System.out.println("equality check between student1 and student2 = " + student1.equals(student2));

  System.out.println("\n\n#######HashSet Test##### With hashCode() and without equals() method ########");
  HashSet<Student> students = new HashSet<Student>();
  students.add(student1);
  students.add(student2);
  System.out.println("HashSet size = " + students.size());
  System.out.println("HashSet contains Amit = " + students.contains(new Student(1, "Amit")));
 }
}
Output:
student1 hashcode = 1
student2 hashcode = 1
equality check between student1 and student2 = false


#######HashSet Test##### With hashCode() and without equals() method ########
HashSet size = 2
HashSet contains Amit = false


As in the above example. I have Override hashCode() but not override equals() methods. So the hashCode of the two object with same value is same. But as per "hashCode and equals contract" they are not  equal. Hence HashSet consider this as two different object and add into HashSet and while i try to get new object with same value its return false because this is new object for HashSet.

In HashSet, add method of HashSet use as below.
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
Adds the specified element into HashSet. If it is not already present. by using as below condition
(e==null ? e2==null : e.equals(e2))
More formally, adds the specified element e to this set if this set contains no element e2 such that

If this set already contains the element, the call leaves the set  unchanged(not added element) and returns false.

With equals() method override and without hashCode()
package hashsetEqualExample;

public class Student {
 private int id;
 private String name;

 public Student(int id, String name) {
  this.name = name;
  this.id = id;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 @Override
 public boolean equals(Object obj) {
  if (obj == null)
   return false;
  if (!(obj instanceof Student))
   return false;
  if (obj == this)
   return true;
  return this.getId() == ((Student) obj).getId();
 }

 /*
  * @Override public int hashCode() { return id; }
  */
}
package hashsetEqualExample;

import java.util.HashSet;

public class HashcodeEquals {

 public static void main(String[] args) {
  Student student1 = new Student(1, "Amit");
  Student student2 = new Student(1, "Amit");
  System.out.println("student1 hashcode = " + student1.hashCode());
  System.out.println("student2 hashcode = " + student2.hashCode());
  System.out.println("equality check between student1 and student2 = " + student1.equals(student2));

  System.out.println("\n\n#######HashSet Test##### With equals() method override and without hashCode() ########");
  HashSet<Student> students = new HashSet<Student>();
  students.add(student1);
  students.add(student2);
  System.out.println("HashSet size = " + students.size());
  System.out.println("HashSet contains Amit = " + students.contains(new Student(1, "Amit")));
 }
}
Output:
student1 hashcode = 1829164700
student2 hashcode = 2018699554
equality check between student1 and student2 = true


#######HashSet Test##### With equals() method override and without hashCode() ########
HashSet size = 2
HashSet contains Amit = false


As in the above example. I have override equals() but not Override hashCode()  methods so the hashCode of the two object with same value are different. even they are equal by equals() method.But because of there hashCode are different. Hence HashSet consider this as two different object and add into HashSet and while i try to get new object with same value its return false because this is new object for HashSet.

With Override hashCode() and equals() method
package hashsetEqualExample;

public class Student {
 private int id;
 private String name;

 public Student(int id, String name) {
  this.name = name;
  this.id = id;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 @Override
 public boolean equals(Object obj) {
  if (obj == null)
   return false;
  if (!(obj instanceof Student))
   return false;
  if (obj == this)
   return true;
  return this.getId() == ((Student) obj).getId();
 }

 @Override
 public int hashCode() {
  return id;
 }
}
package hashsetEqualExample;

import java.util.HashSet;

public class HashcodeEquals {

 public static void main(String[] args) {
  Student student1 = new Student(1, "Amit");
  Student student2 = new Student(1, "Amit");
  System.out.println("student1 hashcode = " + student1.hashCode());
  System.out.println("student2 hashcode = " + student2.hashCode());
  System.out.println("equality check between student1 and student2 = " + student1.equals(student2));

  System.out.println("\n\n#######HashSet Test##### With Override hashCode() and equals() method ########");
  HashSet<Student> students = new HashSet<Student>();
  students.add(student1);
  students.add(student2);
  System.out.println("HashSet size = " + students.size());
  System.out.println("HashSet contains Amit = " + students.contains(new Student(1, "Amit")));
 }
}
Output:
student1 hashcode = 1
student2 hashcode = 1
equality check between student1 and student2 = true


#######HashSet Test##### With Override hashCode() and equals() method ########
HashSet size = 1
HashSet contains Amit = true
Conclusion:
  • It is mandatory to override hashcode() and equals() method each time.
  • If two objects are equal by equals() method, they MUST have the same hash code by overriding hashCode() method.
  • If two objects have the same hash code, they may or may not equal.
  • Overriding equals() alone will fail you business logic with hashing data structures like: HashSet, HashMap, HashTable ... etc.
  • Overriding hashcode() alone, it does not force JVM to ignore memory addresses when comparing two objects. because by default equals() method compare reference like "==" operator.

2 comments: