Wednesday 8 October 2014

Why StringBuffer and StringBuilder has not overridden equals() and hashCode()

Comparing Two Strings:
If we want to compare two strings,we can simply use equals() as below
?
1
2
3
4
5
6
    String str1=new String("ashish");
    String str2=new String("ashish");
     
    System.out.println(str1.equals(str2));//prints true
    System.out.println(str1==str2);//prints false
    System.out.println(str1.hashCode()+":"+str2.hashCode());//returns same value
hashCode() is overrided in String class,and the hashCode is computed using the below formula
 s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]  
So two different String object will give you same hashCode value,if they hold the same value because hashCode for Strings are computed based on the value.
Comparing Two StringBuffer or StringBuilder:
You cannot use equals() to compare two StringBuffer Object.For example
1
2
3
4
5
6
7
8
StringBuffer sb1=new StringBuffer("ashish");
StringBuffer sb2=new StringBuffer("ashish");
     
System.out.println(sb1.equals(sb2));//returns false
System.out.println(sb1.toString().equals(sb2.toString());//use this approach to compare
System.out.println(sb1==sb2);//returns false
         
System.out.println(sb1.hashCode()+":"+sb2.hashCode());//return different value
As we know == always checks for references,and in the above code sb1,sb2 are 2 different instances hence false.
equals() and hashCode() are not overriden in StringBuffer or StringBuilder class,so Object class related equals() and hashCode() will be executed.
Object class equals() checks the reference as below
1
2
3
public boolean equals(Object obj) {
        return (this == obj);
    }
Object class hashCode() is a native method and its implementation depends on JVM provider.However it will return some sort of integer value.
Why equals() and hashCode() was not overridden on StringBuffer and StringBuilder class?
Hashtable was introduced on jdk 1.0 along with StringBuffers,StringBuilder class. (http://web.mit.edu/java_v1.0.2/www/javadoc/packages.html).
Consider two different String object, and we want to put them on Hashtable collection
1
2
3
4
5
6
7
8
9
10
11
String str1=new String("ashish");
String str2=new String("ashish");
     
Hashtable table=new Hashtable();
Object obj1=table.put(sb1, "Spring");//add key,value returns null as its a new entry
Object obj2=table.put(sb2,"Hibernate");replaces old value with new Value and 
returns old value
     
System.out.println(table);
System.out.println(obj1+" "+obj2); //null Spring(old value that was removed)
     
System.out.println(table); //returns {nataraz=Hibernate}
As we know,Hashtable will not allow duplicate key,but allows duplicate value.But as far as our code is concerned,str1 and str2 are 2 brand new different Objects.That means those are not same,and it should be allowed.Right?
Hashtable internally calls  hashCode()  and then equals() to check if both objects are same or not.When you try to store str2 in the hashtable,it checks str2.hashCode()==str1.hashCode() and then str2.equals(str1)
As I have already told you before,String hashCode are calculated based on the content using some formula,both the checks will return true,and Hashtable understands that it is a duplicate object and it will overwrite the Old value with the new value and returns the old value to the program.See the code code of map.put(-,-)
Note: put(key,value) returns null,if key is not duplicate. If key is duplicate,it overwrites the existing value with the new value,and returns the old value to the Programmer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }
        // Makes sure the key is not already in the hashtable.
        Entry tab[] = table;
        int hash = key.hashCode();
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                V old = e.value;
                e.value = value;
                return old;
            }
        }
....
....
}
Sun Microsystem wanted the programmer to allow adding 2 different String kind of Values in Hashtable or any other Hash Collections likes (HashSet,HashMap…),that’s the reason hashCode() and equals() were not overridden intentionally in StringBuffer,StringBuilder class.See the below code for clarity
1
2
3
4
5
6
7
8
StringBuffer sb1=new StringBuffer("ashish");
StringBuffer sb2=new StringBuffer("ashish");
     
Hashtable table=new Hashtable();
Object obj1=table.put(sb1, "Spring");
Object obj2=table.put(sb2,"Hibernate");//2 different object with different hashCode()
System.out.println(obj1+" "+obj2); //null null as both the values will be stored on hashMap
System.out.println(table); //  {ashish=Hibernate, ashish=Spring}
If they would have overridden those two methods,then you would not have been allowed to different StringBuffer,StringBuilder objects with same value as key in Hash collections.
Thank you for reading this Article.If you found it useful,share it on Facebook to reach the needy….

No comments:

Post a Comment