How does the toString()
method, ==
operator, and equals()
method work differently or similarly on reference and primitive types?
The toString method is used to return a string representation of an object. If any object is printed, the toString() method is internally invoked by the java compiler. Else, the user implemented or overridden toString() method is called.
The toString method is used to return the String representation of an object (converting an object to a String). Like equals , all Java objects have a toString method. However, also like equals not all classes provide particularly useful implementations.
When we use the == operator for s1 and s2 comparison, the result is true as both have the same addresses in the string constant pool. Using equals, the result is true because it's only comparing the values given in s1 and s2.
To compare these strings in Java, we need to use the equals() method of the string. You should not use == (equality operator) to compare these strings because they compare the reference of the string, i.e. whether they are the same object or not.
For regular types (including String):
==
compares object references. It tests if two object references are equal; i.e. if they refer to the same object.equals(Object)
tests if this object is "equal to" another one. What "equal to" means depends on how the object's class defines equality. The java.lang.Object
class defines equals(other)
to be this == other
, but many classes override this definition.toString()
provides a simple conversion of the object to a String. The format and content of the resulting String is class specific, and (from the perspective of the java.lang.Object
contract) there are no guarantees that it will be meaningful.For (true) primitive types:
==
compares values of the type, and equals()
and toString()
are not defined. Java does not allow you to call a method on a primitive value.However this is complicated by the fact that in some contexts the Java language says that a primitive type can be "autoboxed" to give an instance of the primitive type's corresponding wrapper type; e.g. int
corresponds to java.lang.Integer
, and so on. For the wrapper classes:
==
is defined the same as for any other reference type, equals()
compares the wrapped values, and toString()
formats the wrapped values. The spanner in the works is illustrated by the following:
int a = ...
int b = a;
Integer aa = a; // autoboxing occurs
Integer bb = b; // autoboxing occurs
assert a == b; // always succeeds
assert aa.equals(bb); // always succeeds
assert aa == bb; // sometimes succeeds, sometimes fails.
The reason that the last sometimes fails is that the JLS does NOT guarantee that autoboxing a given primitive value will always give the same wrapper object. It will in some cases (e.g. for small integers), and won't for others (e.g. large integers).
The lesson to be learned from the example above is that you need to be very careful about using ==
on a reference type. Only use it when you really want to test if two references are to the same object. Don't use it if you just want to test if the objects are "equal" without the overhead of calling equals()
.
(Also note that String
is another type where ==
is going to give you the wrong answer in many situations; see How do I compare strings in Java?.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With