2

I have some doubts regarding equals and hashcode. What I have understood previously is, we need to override the hashcode() and equals() method in the object class if that class is supposed to add to the collection class or Map class. Please see the below example. I did not override the hashcode and equals method. Still I get the desired result what I want. One thing i understood that, If I want to compare two object we need to override the equals method. But in this example I am not comparing two objects, rather I am adding objects to collection or Map without overriding the hashcode and equals. Could anyone explain why do we need to override the hashcode and when?

package equalshashcode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EqualsAndHashCode {
    public static void main(String[] args) {
        Student student1 = new Student("A");
        Student student2 = new Student("B");

        List<Student> studentList = new ArrayList<Student>();

        Map<Integer,Student> studentMap = new HashMap<Integer,Student>();

        studentMap.put(1, student1);
        studentMap.put(2, student2);

        studentList.add(student1);
        studentList.add(student2);

        System.out.println("Student HashMap:: "+studentMap.get(1));
        System.out.println("Before removing::"+studentList);
        System.out.println(studentList.remove(student1));//true success
        System.out.println("After removing::"+studentList);
    }
}

class Student{

    String name;
    public Student(String pName){
        this.name = pName ;
    }

    public String getName(){
        return this.name ;
    }
}
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
user414967
  • 5,225
  • 10
  • 40
  • 61
  • 2
    Look at what happens when you do a `System.out.println(studentList.remove(new Student("A")))`. This will not remove `student1` from the list despite having the same name (which may or may not be the desired effect). If you'd want to construct multiple instances of the same student and use a collection with any of these instances, you'd have to override `equals()` and `hashCode()` – ftr Aug 20 '12 at 12:13

3 Answers3

4

You don't always need to implement equals() and hashCode() to add elements into a collection.

For a List (such as you studentList, which is an ArrayList instance) it doesn't matter for most actions.

The only places where you need equals() and hashCode() is where "equality" of objects is relevant. And even in those places the default implementation might even be sufficient.

Equality matters in several cases, for example:

  • A Set can't contain two objects that are equal to each other
  • The key of a Map must have a correct equals() implementation to be retrievable (and based on the concrete Map implementation, that might imply that hashCode() has to be correctly implemented as well).
  • Some methods on a "normal" List also need equality. For example contains(), indexOf() and remove(Object) need correctly implemented equals()/hashCode()
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
1

Custom equals and hashCode methods are generally used for determining actual equality. If you rely on the default equals method, this will look for the same instance in memory. For example customObj1.equals(customObj2) will return false if there's no custom equals method and the two objects are separate (but otherwise equal) instances. The idea of a custom equals method is to make that same example return true if they are actually equal. A Map will then be able to use this to match the key object passed in a get(key) request to find the value without needing to have the correct instance of the key (a HashMap actually uses hashCode to do this).

The most obvious example of this being useful is for Strings, so that you can do myMap.get("key") and get the correct value, even if your key instance isn't the same as the one stored in the Map (String implements equals and hashCode for you). In general I would recommend using these Java built-in equals and hashCode methods to construct your own. For example if your object has a natural ID, such as say userName, your equals can use the String version of this to complete your own equals (you can obviously compare multiple fields):

public boolean equals(Object o) {
    if (o instanceof MyObj) {
        return userName.equals(((MyObj) o).userName));
    }
    return false;
}

As such, if you'll only be working with a single Thread, or otherwise limited variables, you'll likely never need to implement these methods, but there are certainly times when it pays off to know them.

Vala
  • 5,628
  • 1
  • 29
  • 55
0

Collection classes will work perfectly well with objects that have the default equals/hashCode implementations - there is no need to add your own for this reason.

Custom equals/hashCode methods are easy to get wrong, and unless you have a good reason to roll your own you should just stick with the ones that you get for free with java.lang.Object.

The most common reason for creating your own version of these methods is if you want to treat two separate instances of the same class as being equal. For example, if you have an Account class and you want two instances of Account which have the same accountNumber property to be regarded as equal, because they represent the same real-world account. In this case you would base your equals method on the value of accountNumber alone, and since you now have a custom equals method you need to provide a suitable implementation of hashCode as well, in order to fulfil the equals/hashCode contract.

Community
  • 1
  • 1
codebox
  • 19,927
  • 9
  • 63
  • 81