My understanding is that, when comparing Strings, == compares the references of the Strings, not their values
Indeed; but then replace String
with Object
in the sentence above, or indeed any class implementing Object
(which means, in essence, each and every Java class) and the above sentence will hold...
Except that "values" is too vague.
There is a fundamental contract in Java, and that is Object
's .equals()
and .hashCode()
. They are intrinsically linked to one another. What they essentially define is an equivalence contract.
The base equivalence contract for Object
is simple, really; given two Object
s o1
and o2
, it is true that:
o1.equals(o2)
is strictly equivalent to:
o1 == o2
But it is only because for Object
, .equals()
is defined as such:
// pseudo code...
public boolean equals(final Object o)
{
returns this == o;
}
Now, of course, this won't stand true for String
. A String
has state (its characters), an Object
doesn't. Therefore String
"refines" .equals()
. Which means that even if you have:
String s1 = "hello world";
String s2 = "hello world";
it is not true that:
s1 == s2
(save for particular, irrelevant scenarios), but it is true that:
s1.equals(s2)
As a "side effect", this also means that String
also has to "refine" .hashCode()
as well, since the contract explicitly stipulates that two objects which are equals()
must have the same hashCode()
.