Thursday 18 April 2019

                                                                 equals ( ) in java?

We can use this method to check equivalence of two objects.
If our class doesn't contain .equals() method then object class .equals() method will be executed which is always meant for reference comparison[address comparison]. i.e., if two references pointing to the same object then only .equals( ) method returns true .



class StudentDemo
{
String name;
int rollno;
StudentDemo(String name,int rollno)
{
this.name=name;
this.rollno=rollno;
}
public static void main(String[] args){
StudentDemo s1=new StudentDemo("govind",101);
StudentDemo s2=new StudentDemo("ballabh",102);
StudentDemo s3=new StudentDemo("govind",101);
StudentDemo s4=s1;
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
System.out.println(s1.equals(s4));
}}

Output:
False
False
True





In the above program Object class .equals() method got executed which is always meant for reference comparison that is if two references pointing to the same object then only .equals(() method returns true.
In object class .equals() method is implemented as follows which is meant for reference comparison.

public boolean equals(Object obj) {
return (this == obj);
    }
Based on our programming requirement we can override .equals() method for content comparison purpose.


When ever we are overriding .equals() method we have to consider the following things :
Meaning of content comparison i.e., whether we have to check the names are equal (or) roll numbers (or) both are equal.
If we are passing different type of objects (heterogeneous object) our .equals() method should return false but not ClassCastException i.e., we have to handle ClassCastException to return false.
If we are passing null argument our .equals() method should return false but not NullPointerException i.e., we have to handle NullPointerException to return false.
The following is the proper way of overriding .equals() method for content comparison in StudentTest class.


class StudentTest
{
String name;
int rollno;
StudentTest(String name,int rollno)
{
this.name=name;
this.rollno=rollno;
}
public boolean equals(Object obj)
{
try
{
String name1=this.name;
int rollno1=this.rollno;
StudentTest s2=(StudentTest)obj;
String name2=s2.name;
int rollno2=s2.rollno;
if(name1.equals(name2) && rollno1==rollno2)
{
return true;
}
else return false;
}
catch(ClassCastException e)
{
return false;
}
catch(NullPointerException e)
{
return false;
}
}
public static void main(String[] args){
StudentTest s1=new StudentTest("govind",101);
StudentTest s2=new StudentTest ("ballabh",102);
StudentTest s3=new StudentTest("govind",101);
StudentTest s4=s1;
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
System.out.println(s1.equals(s4));
System.out.println(s1.equals("govind"));
System.out.println(s1.equals("null"));
}

}

Output:
False
True
True
False
False


Simplified version of .equals() method:

public boolean equals(Object o){
try{
  Student s2=(Student)o;
  if(name.equals(s2.name) && rollno==s2.rollno){
    return true;
  }
   else return false;
}
catch(ClassCastException e) {
   return false;
 }
catch(NullPointerException e) {
  return false;
 }
}




More simplified version of .equals() method :

public boolean equals(Object o)  {
  if(this==o)
  return true;
 if(o instanceof Student)  {
     Student s2=(Student)o;
  if(name.equals(s2.name) && rollno==s2.rollno)
     return true;
  else
     return false;
   }
  return false;
}



class StudentTestDemo  {
String name;
int rollno;
StudentTestDemo  (String name,int rollno) {
this.name=name;
this.rollno=rollno;
}
public boolean equals(Object o) {
if(this==o)
return true;
if(o instanceof StudentTestDemo  ) {
StudentTestDemo s2=(StudentTestDemo)o;
if(name.equals(s2.name) && rollno==s2.rollno)
return true;
else
return false;
}
return false;
}
public static void main(String[] args){
StudentTestDemo   s=new StudentTestDemo  ("govind",101);
Integer i=new Integer(10);
StudentTestDemo   s2=new StudentTestDemo  ("govind",101);
System.out.println(s.equals(i));
System.out.println(s.equals(s2));
}
}

output:
false
true


To make .equals() method more efficient we have to place the following code at the top inside .equals() method.
if(this==o)
return true;


If 2 references pointing to the same object then .equals() method return true directly without performing any content comparison this approach improves performance of the system



String s1 = new String("ashok");
String s2 = new String("ashok");
System.out.println(s1==s2);  //false
System.out.println(s1.equals(s2) );  //true

In String class .equals( ) is overridden for content comparision hence if content is same .equals( ) method returns true , even though ths objects are different.

StringBuffer s1 = new StringBuffer("ashok");
StringBuffer s2 = new StringBuffer("ashok");
System.out.println(s1==s2);  //false
System.out.println(s1.equals(s2) );  //false

In StringBuffer class .equals( ) is not overriden for content comparision hence Object class .equals( ) will be executed which is meant for reference comparision , hence if objects are different .equals( ) method returns false , even though content is same.


Relationship between .equals() method and ==(double equal operator) :
If r1==r2 is true then r1.equals(r2) is always true i.e., if two objects are equal by == operator then these objects are always equal by .equals( ) method also.
If r1==r2 is false then we can't conclude anything about r1.equals(r2) it may return true (or) false.
If r1.equals(r2) is true then we can't conclude anything about r1==r2 it may returns true (or) false.
If r1.equals(r2) is false then r1==r2 is always false.
For any object reference r, r==null is always false.

Note : In String class , Wrapper classes and all collection classes .equals( ) method is overriden for content comparision


Differences between == (double equal operator) and .equals() method?
== (double equal operator)
It is an operator applicable for both primitives and object references.
In the case of primitives == (double equal operator) meant for content comparison, but in the case of object references == operator meant for reference comparison.
We can't override== operator for content comparison in object references.
If there is no relationship between argument types then we will get compile time error saying incompatible types.(relation means child to parent or parent to child or same type)

.equals() method
It is a method applicable only for object references but not for primitives.
By default .equals() method present in object class is also meant for reference comparison.
We can override .equals() method for content comparison.
If there is no relationship between argument types then .equals() method simply returns false and we won't get any compile time error and runtime error.
For any object reference r, r.equals(null) is also returns false.


String s = new String("govind");
StringBuffer sb = new StringBuffer("govind");
System.out.println(s == sb); // CE : incomparable types : String and  StringBuffer
System.out.println(s.equals(sb));    //false



Contract between .equals() method and hashCode() method:
If 2 objects are equal by .equals() method compulsory their hashcodes must be equal (or) same. That is If r1.equals(r2) is true then r1.hascode()==r2.hashcode( ) must be true.
If 2 objects are not equal by .equals() method then there are no restrictions on hashCode() methods. They may be same (or) may be different. That is If r1.equals(r2) is false then r1.hashCode()==r2.hashCode() may be same (or) may be different.
If hashcodes of 2 objects are equal we can't conclude anything about .equals() method it may returns true (or) false. That is If r1.hashCode()==r2.hashCode() is true then r1.equals(r2) method may returns true (or) false.
If hashcodes of 2 objects are not equal then these objects are always not equal by .equals() method also. That is If r1.hashCode()==r2.hashCode() is false then r1.equals(r2) is always false.
To maintain the above contract between .equals() and hashCode() methods whenever we are overriding .equals() method compulsory we should override hashCode() method. Violation leads to no compile time error and runtime error but it is not good programming practice.




class Person {
String name;
int age;
Person(String name,int age) {
this.name=name;
this.age=age;
}
public boolean equals(Object o) {
if(this==o)
return true;
if(o instanceof Person) {
Person p2=(Person)o;
if(name.equals(p2.name) && age==p2.age)
return true;
else
return false;
}
return false;
}
public static void main(String[] args){
Person p1=new Person("govind",101);
Person p2=new Person("govind",101);
Integer i=new Integer(102);
System.out.println(p1.equals(p2));
System.out.println(p1.equals(i));
}
}

true
false




Which of the following is appropriate way of overriding hashCode() method?



public int hashCode()
{

returb age;

}



public int hashCode()
{

return age+height;

}

//Incorrect

public int hashCode()
{

return age+height;

}

//Incorrect

public int hashCode()
{

return name.hashCode()+age;

}

//correct

any of the above


Based on whatever the parameters we override ".equals() method" we should use same parameters while overriding hashCode() method also.

Note: in all wrapper classes, in string class, in all collection classes .equals() method is overridden for content comparison in our classes also it is highly recommended to override .equals() method.



case:1  If hash Codes of 2 objects are not equal then .equals() method always return false.(valid)

class Test1{
int i;
Test1(int i) {
this.i=i;
}
public int hashCode() {
return i;
}
public String toString() {
return i+"";
}
public static void main(String[] args) {
Test1 t1=new Test1(10);
Test1 t2=new Test1(20);
System.out.println(t1.hashCode());//10
System.out.println(t2.hashCode());//20
System.out.println(t1.hashCode()==t2.hashCode());//false
System.out.println(t1.equals(t2));//false
}
}

o/p:-------------
10
20
false
false



case2:-If 2 objects are equal by == operator then their hash codes must be same.(valid)

class Test2  {
int i;
Test2(int i) {
this.i=i;
}
public int hashCode() {
return i;
}
public String toString() {
return i+"";
}
public static void main(String[] args) {
Test2 t1=new Test2(10);
Test2 t2=t1;
System.out.println(t1.hashCode());//10
System.out.println(t2.hashCode());//10
System.out.println(t1==t2);//true

}
}

o/p:------------

10
10
true


case:-3 If == operator returns false then their hash codes(may be same (or) may be different) must be different.(invalid)

class Test3 {
int i;
Test3(int i) {
this.i=i;
}
public int hashCode() {
return i;
}
public String toString() {
return i+"";
}
public static void main(String[] args) {
Test3 t1=new Test3(10);
Test3 t2=new Test3(10);
System.out.println(t1.hashCode());//10
System.out.println(t2.hashCode());//10
System.out.println(t1==t2);//false
}
}

o/p:----------
10
10
false



case:-4
If hashcodes of 2 objects are equal then these objects are always equal by == operator also.(invalid)




Note: in all wrapper classes, in string class, in all collection classes .equals() method is overridden for content comparison in our classes also it is highly recommended to override .equals() method. 

No comments:

Post a Comment