Java - How to correctly override equals()


I have my own custom class, MyClass and I want a Set that doesn't allow 2 equal MyClass instances.

The id field uniquely identifies each MyClass instance, thus 2 MyClass instances with the same id are to all purposes equal. The HashSet.add() official Java documentation says that:

"More formally, adds the specified element e to this set if this set contains no element e2 such that (e==null ? e2==null : e.equals(e2))."

Well this might lead you to think that you only need to override MyClass.equals(). This will not work, and in fact if you debug you will find that MyClass.equals() is never called. Here's an example:

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

class MyClass {

 int id = 0;
 String value = null;

 public MyClass(final int id, final String value) {
  this.id = id;
  this.value = value;
 }

 @Override
 public boolean equals(final Object e) {
  final MyClass e2 = (MyClass) e;
  return (e2.id == id);
 }
}

public class Main {

 /**
  * @param args
  */
 public static void main(final String[] args) {
  final Set a = new HashSet();
  System.out.println(a.add(new MyClass(0, "Hello")));
  System.out.println(a.add(new MyClass(1, "World")));
  System.out.println(a.add(new MyClass(0, "World")));
 }
}

The output being:

true
true
true

The problem here is that equals() is only called if hashCode() differs. So you need to override both hashCode() and equals().

Here's an example:

 

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

class MyClass {

    int id = 0;
    String value = null;

    public MyClass(final int id, final String value) {
        this.id = id;
        this.value = value;
    }

    @Override
    public boolean equals(final Object e) {
        final MyClass e2 = (MyClass) e;
        return (e2.id == id);
    }

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

public class Main {

    public static void main(final String[] args) {
        final Set a = new HashSet();
        System.out.println(a.add(new MyClass(0, "Hello")));
        System.out.println(a.add(new MyClass(1, "World")));
        System.out.println(a.add(new MyClass(0, "World")));
    }
}

Running this will output:

true
true
false
 
Which is exactly what we wanted.

Comments

Popular Posts