StringBuffer sb1 = new StringBuffer("Java");
StringBuffer sb2 = new StringBuffer("Java");
System.out.println(sb1 == sb2);
System.out.println(sb1.equals(sb2));
Here both are returning false. How is it possible?
The equals
method of StringBuffer
is not overridden from Object
, so it is just reference equality, i.e., the same as using ==
. I suspect the reason for this is that StringBuffer
is modifiable, and overriding equals
is mostly useful for value-like classes that you might want to use as keys (though lists also have an overridden equals
and StringBuffer
is kind of a list, so this is a bit inconsistent).
You are comparing the references to the StringBuffer objects rather than the actual strings within the StringBuffer.
System.out.println(sb1.toString().equals(sb2.toString()))
would return true and I assume this is what you had expected or wanted to achieve.
1. System.out.println(sb1 == sb2);
StringBuffer's equals method returns true only when a StringBuffer object is compared with itself. It returns false when compared with any other StringBuffer, even if the two contain the same characters.
This is because "==" checks the reference equality and since both sb1 and sb2 are different object references, so the output in this case is "false"
Still if you want to check if the content is equal in these two StringBuffer Objects, you can use this:
sb1.toString().equals(sb2.toString())
2. System.out.println(sb1.equals(sb2));
This is giving output as "false" because .equals() method has not been overridden in the StringBuffer Class. So it is using the .equals() method from its parent "Object" class. In the object class .equals() has been written to check the reference equality.
Note that sb3.equals(sb4) will return "true" in case of String. Because .equals() method has been overridden in String class to check and match the content of two different Strings.
The simple answer is that StringBuffer
(and StringBuilder
) do not override the base semantics of Object.equals()
. So equals
on a StringBuffer
will simply compare object references.
In fact, String
, StringBuffer
, StringBuilder
and CharBuffer
all implement the CharSequence interface, and the javadoc for this interface says this:
This interface does not refine the general contracts of the
equals
andhashCode
methods. The result of comparing two objects that implementCharSequence
is therefore, in general, undefined. Each object may be implemented by a different class, and there is no guarantee that each class will be capable of testing its instances for equality with those of the other. It is therefore inappropriate to use arbitraryCharSequence
instances as elements in a set or as keys in a map.
Also note that javadocs for StringBuffer
(and StringBuilder
) explicitly states this:
API Note:
StringBuffer
implementsComparable
but does not overrideequals
. Thus, the natural ordering ofStringBuffer
is inconsistent withequals
. Care should be exercised ifStringBuffer
objects are used as keys in aSortedMap
or elements in aSortedSet
.
But why?
At the heart of it is the fact that String
is immutable and StringBuffer
/ StringBuilder
are mutable.
If two String
objects have the same characters, they will always have the same characters. So it is natural to treat them as equal ... and that is what String::equals(Object)
does.
If two StringBuffer
objects can have the same characters now, and different characters a moment later ... due to a mutating operation performed by another thread. An implementation of equals(Object)
for StringBuffer
that was sensitive to the (changing) content would be problematic. For example:
if (buf1.equals(buf2)) {
// Do something to one of the StringBuffer objects.
}
has a potential race condition. Another example is use of StringBuffer
instances as keys in HashTable
or HashMap
.
At any rate, a deliberate design decision taken a very long time ago that StringBuffer
and StringBuilder
would not override the Object::equals
and Object::hashCode
methods.
StringBuffer
seems to have no equals
method of its own, so my first guess would be that StringBuffer
inherits the equals
method of Object
, which compares using sb1 == sb2
. Therefore, both methods yield the same result.
both compares two references to objects (sb1 is one, and sb2 is second), thus both are different.
If You are trying to compare content - use method compareTo(...) in String class - that is - first get String content of StringBuffer using method toString() (.toString().compareTo).
Ps. as of JDK 5, there is another much faster class that behaves exactly as StringBuffer - it is StringBuilder, and is also but is not thread safe.
StringBuffer sb1 = new StringBuffer("Java");
StringBuffer sb2 = new StringBuffer("Java");
System.out.println(sb1.toString().compareTo(sb2.toString()));
Wondering why StringBuffer
does not override the equals
method. Probably because the content of the object is obtained by the toString()
method and which has the desired method.
With JDK/11, one can now compare two StringBuffer
s without an additional toString
, this can be done using the newly introduced API -
public int compareTo(StringBuffer another)
Compares two
StringBuffer
instances lexicographically. This method follows the same rules for lexicographical comparison as defined in theCharSequence.compare(this, another)
method. For finer-grained, locale-sensitive String comparison, refer to Collator.Implementation Note: This method synchronizes on this, the current object, but not StringBuffer another with which this StringBuffer is compared.
Returns: the value 0 if this StringBuffer contains the same character sequence as that of the argument StringBuffer; a negative integer if this StringBuffer is lexicographically less than the StringBuffer argument; or a positive integer if this StringBuffer is lexicographically greater than the StringBuffer argument.
Sample usage :
StringBuffer stringBuffer = new StringBuffer("null");
StringBuffer anotherStringBuffer = new StringBuffer("NULL");
System.out.println(stringBuffer.compareTo(anotherStringBuffer) == 0); // shall print 'false'
Stringbuffer's equals()
is not overridden. It does not compare values, it only compares reference value assignments. That is why you are getting false as they both are referring to different objects.
That is tricky let me explain you in Object class equals method functionality is to match reference based on objects Sun developers had overridden the equals method in Collection, String, Wrapper classes so except this classes if you apply equals method anywhere it will check reference not content because indirectly every class in java is the child of Object class so if you want to check content in StringBuffer class you can override the object class equals method Thanks.
-> The String, StringBuffer and StringBuilder extends Object class.
-> Object class contain equals() which compare two object memory address/ reference.
-> The equals() method is overridden in String class and it will check the
content.tostring()
System.out.println(sbuffer1.toString().equals(sbuffer2.toString()))
-> The equals() method of StringBuffer is not overridden from Object but implements Comparable, so it will compare reference equality, i.e., the same as using ==. in string class and equals() method in object.class. Thus, the natural ordering of StringBuffer is inconsistent with equals.