Wednesday, 2 November 2016

Java Source World: Implementing equals() and hashcode()


                                                           Java Source World                       A Java quick reference blog




Implementing equals() and hashcode()




All objects have both identity (the object's location in memory) and state (the object's data). The == operator always compares identity. The default implementation of equals compares identity as well.

Sometimes the default implementation of equals has the desired behaviour (as in a type-safe enumeration, for example), but equals should usually compare state, not identity. This is particularly true for "data-centric" classes which map to database records.

hashCode and equals are closely related:


  • if you override equals, you must override hashCode.
  • hashCode must generate equal values for equal objects.

equals and hashCode must depend on the same set of "significant" fields. You must use the same set of fields in both of these methods. You are not required to use all fields.

 For example, a calculated field that depends on others should very likely be omitted from equalsand hashCode.

Objects placed in a List, Set, or Map (as either a key or value) should have an appropriate definition of equals. (See, for example, the javadoc for Collection.contains , Map.containsKey, and Map.containsValue .)

If you extend a concrete class, and add a new field which contributes to equals, then it's not possible to write a perfectly correct equalsmethod for the new class. Instead, you should use composition instead of inheritance. (See Effective Java by Joshua Bloch for more information.)

When implementing equals, fields are compared differently, according to their type:

  • object fields, including collections : use equals
  • type-safe enumerations : use either equals or == (they amount to the same thing, in this case)
  • possibly-null object fields : use both == and equals
  • array fields : use Arrays.equals
  • primitive fields other than float or double : use ==
  • float : convert to int using Float.floatToIntBits, then use ==
  • double :  convert to long using Double.doubleToLongBits, then use ==




It's worth noting that if fields are implemented with wrapper classes (Integer, Boolean, and so on), then implementation of equals is simpler, since there is only one case: calling the equals method recursively. (The compareTo method is also simplified in this case.)

In an equals method, it's usually worthwhile to order field comparisons such that the most significant comparisons are performed first. That is, fields most likely to differ should be evaluated first. This allows the && "short-circuit" logical operator to minimize execution time.


Find the example code below:

AccountPK.java


package com.core.equalstest;

public class AccountPK {

    private String companyCode;

    private String accountInfoIdentifier;

    private int serialNumber;
   
    /**
     *
     * @param other
     * @return
     */
    public boolean equals(Object other) {
            return (other != null) && ((hashCode() == other.hashCode()));
      }
    /**
     *
     * @return
     */
      public int hashCode() {
         
            return new StringBuffer(companyCode).
                        append(accountInfoIdentifier).
                        append(serialNumber).
                        toString().hashCode();
      } 


      public void setCompanyCode(java.lang.String companyCode) {
            this.companyCode=companyCode;
      }
      public java.lang.String getCompanyCode() {
            return this.companyCode;
      }


      public void setSerialNumber(int serialNumber) {
            this.serialNumber=serialNumber;
      }
      public int getSerialNumber() {
            return this.serialNumber;
      }


      public void setAccountInfoIdentifier(java.lang.String                                      accountInfoIdentifier) {
            this.accountInfoIdentifier=accountInfoIdentifier;
      }
      public java.lang.String getAccountInfoIdentifier() {
            return this.accountInfoIdentifier;
      }
      @Override
      public String toString() {
            StringBuilder sbul = new StringBuilder(199);
            sbul.append("AccountPK [ ");
            sbul.append("accountInfoIdentifier '").append(
                        this.accountInfoIdentifier);
            sbul.append("', companyCode '").append(this.companyCode);
            sbul.append("', serialNumber '").append(this.serialNumber);
            sbul.append("' ]");
            return sbul.toString();
      }

}

In the above code, we can understand that how the equals and hascode methods are implemented in the AccountPK.java.

Now we will try to understand the implementation of equals() and hashcode().

The AccountPK.java is having the properties  called companyCode,  accountInfoIdentifier,  serialNumber.

The below code returns true or false by comparing the hashCode() method generated hashcode and the hashcode passed object's hashcode in the equals method .


public boolean equals(Object other) {
            return (other != null) && ((hashCode() == other.hashCode()));
      }

The below method generates the hascode of the given properties in the Accoutn.java.

public int hashCode() {
              return new StringBuffer(companyCode).
                        append(accountInfoIdentifier).
                        append(serialNumber).
                        toString().hashCode();
      } 

In interviews you may face the fallowing questions about equals() and hascode()

When you are writing equals() method, which other method or methods you need to override?


hashcode, is the right answer. Since equals and hashCode has there contract, so overriding one and not other, will break contract between them. By the way this question can lead on interesting discussion, if Interviewer likes to go on deep e.g. he may ask about what are those contracts, what happens if those contracts breaks etc. I like to give an example How equals and hashcode are used in hash based collections e.g. Hashtable, that leaves positive impression more often. You can also mention about compareTo() here to score some additional point, this method should also needs to be consistent with equals, which is another interesting question in our list.


Can two object which are not equal have same hashCode?


YES, two object, which are not equal by equals() method can still return same hashCode. By the way, this is one of the confusing bit of equals and hashcode contract.



How does get() method of HashMap works, if two keys has same hashCode?



This is the follow-up of previous interview questions on equals and hashcode, in fact some time this leads to discussion of the earlier point. When two key return same hashcode, they end-up in same bucket. Now, in order to find the correct value, you usedkeys.equals() method to compare with key stored in each Entry of linked list there. Remember to point out keys.equals() method, because that's what interviewer is looking for. 

What is difference between "==" and equals() method in Java?



One of the most classical interview question on equals(). It has been asked numerous times during in past decade.


You may also like the fallowing posts:






Implementing equals() and hashcode() | Java Source World

                                                           Java Source World                         A Java quick reference blog



No comments:

Post a Comment