Unlike String, StringBuffer1 is a mutable type. True to this design, StringBuffer.reverse modifies the original object and then returns the same (current) StringBuffer instance; returning the same instance allows for method-chaining:
[reverse] causes this character sequence to be replaced by the reverse of the sequence [and returns] a reference to this [StringBuffer] object.
Thus
StringBuffer w=p.reverse();
is semantically equivalent to
p.reverse(); // side-effect! reverses content StringBuffer w == p; // w == p -> true (same object), implies w.equals(p) -> true
One approach to solve this is to create a new StringBuffer instance for w, and reverse after.
StringBuffer w = new StringBuffer(p); // w == p -> false, w.equals(p) -> true p.reverse(); // w == p -> false, w.equals(p) -> false
If only needing a String, the same rules/logic apply - create a new object/copy of the data before reversing the StringBuffer.
String s = p.toString() // s == p -> false, s.equals(p) -> true p.reverse(); // s == p -> false, s.equals(p) -> false
While I doubt this is the actual task, consider p.toString.equals(p.reverse()) which also follows the preceding logic.
boolean reversed = p.toString() // "s", new String / data copy .equals( p.reverse() // "p", reverse done after copy );
1 StringBuffer is old, use StringBuilder going forward unless the synchronization properties are required:
[StringBuilder] is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single threaded.. Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.
equalsIgnoreCase()?