JoBins採用企業サイト JoBinsエージェントサイト

アカウントをお持ちの方はこちら 採用企業ログイン
エージェントログイン


background

Equals method on java

Feb 15, 2019

Equals Method in Java.

The object class in Java is a superclass for all the classes, meaning all the classes directly or indirectly inherit from the Object class.

This indicates all the classes will have inherited all the public methods from the Object class, among other methods the equals method is a very significant method that exists in all classes in a java program.

This method can be overridden depending on the needs of a program, however, there exists an explicit general contract that they must follow. While these contracts are not absolutely needed for the class to run in the JVM some other classes depend on these methods to work correctly.

The other classes that depend on the general contract of these superclass’s methods are HashMap and HashSet.

When should the method  Object.equals be overridden?  

That would be when a class has a notion of logical equality that varies from poor object identity and a superclass hasn’t already overridden the equals method.
This is generally the case for value classes.

A value class is simply a class that represents a value, like the wrapper classes such as Integer or Date.

When object references are compared to value objects using the equals method it is expected to find if the classes are logically equivalent, not whether they refer to the same object.

However, enum types fall into the category where a value class that does not require the equals method to be overridden because it uses instance control to ensure that at most one object exists with each value.

From the Specification for Object [JavaSE6]:

The equals method must implement an equivalence relation like:

  • Reflexive: For any non-null reference value x , x.equals(x) must return true .
  • Symmetric: For any non-null reference values x and y , x.equals(y) must return true if and only if y.equals(x) returns true .
  • Transitive: For any non-null reference values x , y , z , if x.equals(y) returnstrue and y.equals(z) returns true , then x.equals(z) must return true .
  • Consistent: For any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x , x.equals(null) must return false .

The specification itself could be very daunting to understand but if the general contract is not followed when overriding the equals method a program can behave faultily or even crash in extreme conditions, and it can be rather quickly a difficult task to pin down the source of the failure.

  • Reflexivity The first requirement simply states that an object must be equal to itself.
  • Symmetry The second requirement states that any two objects must agree on whether they are equal.

For example, equals methods in new String extended class.


public final class TestString {
private final String s;
    public TestString(String s) {
        if (s == null)
            throw new NullPointerException();
            this.s = s;
    }
@Override 
public boolean equals(Object o) {
        if (o instanceof TestString)
            return s.equalsIgnoreCase(
                ((TestString) o).s);
        if (o instanceof String) // One-way interoperability!
            return s.equalsIgnoreCase((String) o);
        return false;
    }
}

The equals method in this class attempts to compute with ordinary strings.

Let’s suppose that we have one case-insensitive string and one ordinary one:

TestString ts = new TestString("Polish");
String s = "polish";

In which case

ts.equals(s);

returns true. The problem is that while the equals method in TestString knows about ordinary strings, the equals method in String is unaware of case-insensitive strings.

Therefore s.equals(cis) returns false, which would be a clear breaking of symmetry.

If  TestString is put into a collection:


List list = ArrayList();
list.add(ts)

In Sun’s current implementation,

list.contains(s);

happens to return false, but that’s just an implementation artifact.

In another implementation, it could just as easily return true or throw a runtime exception. Once the equals contract is breached, it’s not uncommon for how other objects will behave when confronted with the object.

  • Transitivity If one object is equal to a second and the second object is equal to a third, then the first object must be equal to the third.
  • Consistency The fourth requirement of the equals contract says that if two objects are equal, they must remain equal for all time unless one (or both) of them is modified. In other words, mutable objects can be equal to different objects at different times while immutable objects can’t.
  • The final requirement says that all objects must be unequal to null. This rule seems self-explanatory in itself.

While all the general contract is maintained while overriding the Equals method, the general contract for the HashCode method, another one of the methods present on the Object class is, after overriding the equals method it is necessary to override the HashCode method as well but that would be a topic for another blog entirely.