Saturday 13 April 2013

Understanding equals() and hashCode() methods in Java.

You must have heard that whenever you write a class of your own, you must always override equals() and hashCode()  methods.Lets us understand these methods and why it is important to override these methods.

Both these methods are defined in the Object class which is the top most class in the inheritance hierarchy. All classes implicitly extend object class and hence all class have these methods. Hence you must override these methods to suit your class requirements. Why and where they are used - we will come to it in some time.

Understanding motive behind the functions

     .equals() method is used to compare two objects. Since you only know the structure of your class you are the only one who can implement the comparison logic. For more details on this you can refer post on .equals() method. 

   .hashCode() method is used to return a unique integer value for each unique object. This unique number is used in various cases like while storing the objects in Map etc.So the motive is if two objects are same i.e if they return true on .equals() method then they must also return the same hashcode. So logic similar to .equlas() must be added to return a unique integer(hashcode) for unique objects.

Note : Reverse is not true. If two objects return the same hashcode they may or may not be same objects.

Default Implementation

public boolean equals(Object object) {
    return this == object;
}

public int hashCode() {
    return VMMemoryManager.getIdentityHashCode(this);
}

Summary

   Both your equals() and hashCode() are implementations of the programmer. Make sure to use same attributes in both these function. Whenever you override equals() method make it a point to override
hashCode() too. Key point to remember is if two objects are same they must return true from .equals() method and also they must return same hashcode from .hashCode() method.

If you are using an IDE like eclipse you can directly generate hashCode() and equals() just like generating getter and setter methods.Then add your overriding logic. Here is a snapshot of eclipse - 


Difference between using == operator and equals() method in Java

This is a very basic question and most frequently asked in interviews.  It is very important to understand the difference before you write complex Java programs.

   Let us start with == operator first.We know this is a comparator operator but the question is how does it actually work and how is it different from .equals() method?

== operator

       == operator compares whether the two references that are compared point to the same object or not. Result will be true if both references point to the same object else it is false.Lets take an example to understand this better.

package testCodes;

public class Test {
   
    public static void main(String args[])
    {
        String name1 = new String("John");
        String name2 = name1;
        if(name1 == name2)
        {
            System.out.println("Both references point to the same object \n");
        }

        else

        {   

            System.out.println("Both references point to different objects \n");

         }
    }
}

output : Both references point to the same object

In above code we create a String object name1 with value John. Then we create a reference name2 and make it point to the same object created earlier. Then we compare both references and as both references point to same object with value John == operator return true and hence we get our desired output. Lets say we do something like below -

String name1 = new String("John");

String name2 = new String("John");

if(name1 == name2)

{
    System.out.println("Both references point to the same object \n");

} 

else

{   

    System.out.println("Both references point to different objects \n");

}


 output : Both references point to different objects

As expected if we create two different objects, though both contain the same value John we get false from == operator as references point to two different object and else part is printed.

Note if you do something like

String name1 = "John";

String name2 = "John";

if(name1 == name2)

{
    System.out.println("Both references point to the same object \n");

} 

else

{   

    System.out.println("Both references point to different objects \n");

}


 output : Both references point to the same object

This is because when you don't create explicit objects, Java internally stores this data in a pool on the heap and any string created with  John as the value will point to this data in the pool.This is data is stored in an object called interned String objec. Hence they refer to same object and == return true. For more details refer the tutorial on Difference between String Object and String Literal.

To sum this up == operator check whether the two references which are being compared point to same object or not.

.equals() method

     This method is very much straight forward. It will simple check if the two objects are internally same or not. In case of String it will check if both objects have same value or not. If you are creating an object of your own you must override this  method to handle equality.

The default implementation of .equals() method is as follows -  

public boolean equals(Object other) 
     return this == other;   

Yes that's right! By default .equals() method is same as using == operator. Hence for custom classes you must override this method by adding logic to compare  your objects.

For example if you are making a Coordinate class which has x and y coordinates as instance variable you may override .equals() method as follows - 


public boolean equals(Object other) 
     if((Coordinate)other.x == this.x  && (Coordinate)other.y == this.y)
     {
         return true;
      }
    else
     {
        return false;
      } 

Above code just compare if x coordinate and y coordinate of both coordinate objects are same. If yes then the objects are similar and true is returned else false is returned. I hope you get the point.Also don't forget to override hashCode()method. We will learn this hashCode() method and why to override this in next tutorials but for now just keep that in mind.



Summary


    == operator check whether both the objects compared point to the same object or not while .equals() method is overridden and implemented by the programmer. .equals() method is provide to provide functionality to compare similarity of two objects. If it is not overridden then it is same as using ==  operator.


Related Links




Difference between string object and string literal

Background


Everybody is familiar with Strings as a data type. Strings can be used as literals 
  • String name = "John";
or they can be used as objects
  • String name = new String("John");
They may behave the same way and may serve our purpose equally but do we really understand what are the differences between the two. How both the Strings behave and how would it affect our programming logic.

Lets understand the differences between the two and when we would use each....

Note 1: First thing everyone must remember is that Strings are immutable i.e they cannot be changed or altered. Of-course you can perform operations on it like substring()  but this will give you entirely different String. Point here is that once you create a String you cannot modify it.

Using String as a Literal

    You create a String literal simply as below - 
  • String name = "John";
  When you create a String literal it is stored in PermGen area of the Heap(The PermGen normally consists of the string literal pool and loaded classes).

Note 1: From Java 7, String pool is moved from permgen to normal heap area. This was primarily because permgen ares is of fixed size and may led to "java.lang.OutOfMemoryError: PermGen space" finally leading your JVM to crash.  

Note 2: From Java 8 there is no permgen area. All classes are loaded in normal heap are only. 

So now when you create a String as a literal reference point to an object called interned String object which is created in the PermGen of the Heap i.e name will refer to an interned String object. This means, that the character sequence "John" will be stored at a central place and whenever the same literal "John" is used again, the JVM will not create a new String object but use the reference of the 'cached' String.

Note : String literals are interened by default.


To clarify this further lets take an example - 

String name1 = "John";
String name2 = "John";
if(name1 == name2)
{
   System.out.println("Both point to same object \n"); 
}
if(name1.equals(name2))
{

    System.out.println("Both have same value \n");
}

output :
 Both point to same object
 
Both have same value

Hope you get the point now. Object is the same (created once in PermGen area) and is referred every time a literal with same value is referred. So to summarize objects are same and obvious the value too.

Lets understand creating String as an object now.

Using String as an Object

     Creating String as an object is as follows -
  •    String name = new String("John");
Here name  is an individual instance of the java.lang.String class. This object is created just as other objects in the heap.Two objects created with new keyword will always point to two different objects even if their values are same.
Let's take an example to understand this - 


String name1 = new String("John");
String name2 = new String("John");
if(name1 == name2)
{
   System.out.println("Both point to same object \n");
}
if(name1.equals(name2))
{

    System.out.println("Both have same value \n");
}

output :
Both have same value           

As expected we did not get  Both point to same object as our output as both objects are entirely different and are allocated separate memory.But note that they have same value i.e  John and hence we got the output as Both have same value.


As I mentioned earlier String literals are interened by default. But if you need to intern an String Object you need to call  intern() on it.

        String name1 = new String("John").intern();
        String name2 = new String("John").intern();
        if(name1 == name2)
        {
           System.out.println("Both point to same object \n");
        }
        if(name1.equals(name2))
        {
        
            System.out.println("Both have same value \n");
        }
output :
 Both point to same object
 
Both have same value

String pool values are garbage collected

Irrespective of which version of Java you use and where you String pool resides, values of String pool are eligible for GC and follow normal GC rules i.e if they are not reachable from from program GC roots then they are eligible for garbage collection.

Though this is true String literals may not be candidates for GC in most of the cases.  String literals will always be accessible from GC roots as the code will have implicit reference to it. For example a method that uses a string literal will always have a reference to it. So this literal will be garbage collected only if that code referencing it is GCed and that is not possible unless the class/code is dynamically loaded.

If the literal was defined in a class that was dynamically loaded (e.g. using Class.forName(...)), then it is possible to arrange that the class is unloaded. If that happens, then the String object for the literal will be unreachable, and will be reclaimed when the heap containing the interned String gets GC'ed. 

Also this happens on full GC.

Summary

   To summarize what we learned above -  When we create String as a literal it is created as an interned object in PermGen area of the Heap (Normal area of heap from Java 7) and will be referred every time a  literal is created with same value. On the other hand separate object is created every time String is created as an object using new keyword.


Related Links

t> UA-39527780-1 back to top