Re: String comparison using equals() and ==
According to Chanchal <chanchal.jacob@gmail.com>:
I always thought that we should not use == for comparing two different
String objects because == will compare the references and will never
return true even when the value of the compared Strings are the same
You should not use '==' when comparing String objects because '==' will
compare the references and _may_ return false even for strings with the
same contents. But it may also return true if the references happen to
be the same.
There is an "internal pool" of String instances which acts as a
unifying map. To access this pool you have to call the String.intern()
method. Like this:
String foo = ...;
String bar = foo.intern();
All literal strings (the one which correspond to the '"blah"' syntaxic
constructions in source code) are automatically interned. Thus, the
following code:
String foo = ...;
if (foo.equals("foo_ref")) {
...
}
can be replaced with:
String foo = ...;
String bar = foo.intern();
if (bar == "foo_ref") {
...
}
because if the contents of 'foo' are equals to those of the literal
string '"foo_ref"', then 'bar' (the interned version of 'foo') will be
the reference to the literal string itself.
String.intern() is rarely used because it could be somewhat expensive
(if only because a shared pool implies synchronization at some point)
and it relies on allocation details which are not stressed upon by the
overall Java syntax, making this usage a bit difficult to read (the
whole point of the equals() method is to make such allocation details as
invisible as possible).
Also, some older versions of Sun's JVM allocated interned strings in the
"permanent generation", a smart name for what is more commonly known as
"memory leak" and is generally frowned upon. Newer JVM appear to use
weak references (or a similar mechanism) to handle that map, so the
problem does not occur anymore, but it is plausible that a synchronized
map with weak references has an overall cost which is higher than using
plain equals() on strings. As an amusing example, run the following code:
public class Foo {
public static void main(String[] args)
{
int v = Integer.parseInt(args[0]);
String z = Integer.toString(v);
System.out.println(System.identityHashCode(z.intern()));
z = null;
System.gc();
z = Integer.toString(v);
System.out.println(System.identityHashCode(z.intern()));
}
}
(To launch with "java Foo 42" or any other integer argument.)
With my machine (Sun's JVM 1.6.0_14, Linux, amd64), this prints out
two distinct integers, which means that the two calls to intern()
did not return a reference to the same String instance, even though
they operated on strings with identical contents.
To sum up: use equals() and you will live happier.
--Thomas Pornin