13

I´ve often found an equals method in different places. What does it actually do? Is it important that we have to have this in every class?

   public boolean equals(Object obj)
    {
    if (obj == this)
    {
        return true;
    }
    if (obj == null)
    {
        return false;
    }
    if (obj instanceof Contact)
    {
        Contact other = (Contact)obj;
        return other.getFirstName().equals(getFirstName()) &&
                other.getLastName().equals(getLastName()) &&
                other.getHomePhone().equals(getHomePhone()) &&
                other.getCellPhone().equals(getCellPhone());

    }
    else
    {
        return false;
    }
}
Best
  • 2,200
  • 9
  • 30
  • 49
  • 4
    I assume you've already looked at the documentation, which spells it out pretty clearly: http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html [scroll down to equals() as the direct link doesn't seem to work in commments]. – NPE Dec 01 '11 at 08:26

7 Answers7

34

It redefines "equality" of objects.

By default (defined in java.lang.Object), an object is equal to another object only if it is the same instance. But you can provide custom equality logic when you override it.

For example, java.lang.String defines equality by comparing the internal character array. That's why:

String a = new String("a"); //but don't use that in programs, use simply: = "a"
String b = new String("a");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true

Even though you may not need to test for equality like that, classes that you use do. For example implementations of List.contains(..) and List.indexOf(..) use .equals(..).

Check the javadoc for the exact contract required by the equals(..) method.

In many cases when overriding equals(..) you also have to override hashCode() (using the same fields). That's also specified in the javadoc.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
12

Different classes have different criteria for what makes 2 objects "equal". Normally, equals() returns true if it is the same Object:

Object a = new Object();
Object b = new Object();
return(a.equals(b));

This will return false, eventhough they are both "Object" classes, they are not the same instance. a.equals(a) will return true.

However, in cases like a String, you can have 2 different instances but String equality is based on the literal characters that make up those Strings:

String a = new String("example");
String b = new String("example");
String c = new String("another");
a.equals(b);
a.equals(c);

These are all different instances of String, but the first equals will return true because they are both "example", but the 2nd will not because "example" isn't "another".

You won't need to override equals() for every class, only when there is a special case for equality, like a class that contains 3 Strings, but only the first String is used for determining equality. In the example you posted, there could have been another field, description which could be different for 2 different "Contacts", but 2 "Contacts" will be considered equal if those 4 criteria match (first/last name, and home/cell phone numbers), while the description matching or not matching doesn't play into whether 2 Contacts are equal.

Jon Lin
  • 142,182
  • 29
  • 220
  • 220
10

Aside from everything given by Bozho, there are some additional things to be aware of if overriding equals:

  • something.equals(null) must always return false - i.e. null is not equal to anything else. This requirement is taken care of in the second if of your code.

  • if it is true that something == something else, then also something.equals(something else) must also be true. (i.e. identical objects must be equal) The first if of your code takes care of this.

  • .equals SHOULD be symetric for non-null objects, i.e. a.equals(b) should be the same as b.equals(a). Sometimes, this requirement breaks if you are subclassing and overriding equals in the parent-class and in the subclass. Often equals contains code like if (!getClass().equals(other.getClass())) return false; that at least makes sure that a diffrent object type are not equal with each other.

  • If you override equals you also MUST override hashCode such that the following expression holds true: if (a.equals(b)) assert a.hashCode() == b.hashCode(). I.e. the hash code of two objects that are equal to each other must be the same. Note that the reverse is not true: two objects that have the same hash code may or may not be equal to each other. Ususally, this requirement is taken care of by deriving the hashCode from the same properties that are used to determine equality of an object.

In your case, the hashCode method could be:

public int hashCode() {
  return getFirstName().hashCode() +
    getLastName().hashCode() +
    getPhoneHome().hashCode() +
    getCellPhone().hashCode();
}
  • If you implement Comparable that compares two objects if they are smaller, larger, or equal to each other, a.compareTo(b) == 0 should be true if and only if a.equalTo(b) == true

In many IDEs (e.g. Eclipse, IntelliJ IDEA, NetBeans) there are features that generate both equals and hashCode for you, thereby sparing you of tedious and possibly error-prone work.

nd.
  • 8,699
  • 2
  • 32
  • 42
3

The equals method is used when one wants to know if two objects are equivalent by whatever definition the objects find suitable. For example, for String objects, the equivalence is about whether the two objects represent the same character string. Thus, classes often provide their own implementation of equals that works the way that is natural for that class.

The equals method is different from == in that the latter tests for object identity, that is, whether the objects are the same (which is not necessarily the same as equivalent).

ibid
  • 3,891
  • 22
  • 17
1

It enables you to re-define which Objects are equal and which not, for example you may define that two Person objects as equal if the Person.ID is the same or if the Weight is equal depending on the logic in your application.

See this: Overriding the java equals() method quirk

Community
  • 1
  • 1
CloudyMarble
  • 36,908
  • 70
  • 97
  • 130
0

By default, the Object class equals method invokes when we do not provide the implementation for our custom class. The Object class equals method compares the object using reference.

i.e. a.equals(a); always returns true.

If we are going to provide our own implementation then we will use certain steps for object equality.

    Reflexive:  a.equals(a) always returns true;

    Symmetric: if a.equals(b) is true then b.equals(a) should also be true.

    Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.

    Consistent: a.equals(b) should be the same result without modifying the values of a and b.

Note: default equals method check the reference i.e. == operator.

Note: For any non-null reference value a, a.equals(null) should return false.

public class ObjectEqualExample{

     public static void main(String []args){
        Employee e1 = new Employee(1, "A");
        Employee e2 = new Employee(1, "A");

        // if we are using equals method then It should follow the some properties such as Reflexive, Symmetric, Transitive, and constistent
        /* 
        Reflexive:  a.equals(a) always returns true;
        Symmetric: if a.equals(b) is true then b.equals(a) should also be true.
        Transitive: If a.equals(b), b.equals(c) then a.equals(c) should be true/false according to previous 2 result.

        Consistent: a.equals(b) should be the same result without modifying the values of a and b.

        Note: default equals method check the reference i.e. == operator.
        Note: For any non-null reference value a, a.equals(null) should return false
        */
        System.out.println(e1.equals(e1));
        System.out.println(e1.equals(e2));
     }
}

class Employee {
    private int id;
    private String name;

    @Override
    public String toString() {
        return "{id ="+id+", name = "+name+"} ";
    }

    @Override
    public boolean equals(Object o) {
        // now check the referenc of both object
        if(this == o) return true;

        // check the type of class
        if(o == null || o.getClass() != this.getClass()) return false;

        // now compare the value
        Employee employee = (Employee)o;
        if(employee.id == this.id && employee.name.equals(this.name)) {
            return true; 
        } else return false;
    }

    public int hashCode() {
         // here we are using id. We can also use other logic such as prime number addition or memory address.
        return id;
    }

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

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}
0

One more thing, maps use the equals method to decide if an Object is present as a key. https://docs.oracle.com/javase/8/docs/api/java/util/Map.html

gefdel
  • 59
  • 1
  • 7