Some java programmers forget that a text is stored in different areas and that this affects the use of direct comparisons. This page attempts to show why equals and equalsIgnoreCase methods from the String class should always be used.
A java text segment can be stored as a literal in a "string pool" or as data inside a String object.
String a = "abc"; // text stored in string pool
String b = "abc"; // ref to text already in string pool
(a == b): true
These literal values can be compared directly because they will hold the same pointer.
However, text used to initialise a new String object cannot be compared in this way as each object will hold its own text fragment. These objects are stored directly in the heap. So, comparing String object with String Pool text does not work directly:
String c = new("abc"); // c String object stored on heap with own pointer
(c == b): false
Using the equals and equalsIgnoreCase methods from the String class does work:
(c.equals(b)): true
String objects will also have different addresses on the heap so also cannot be compared directly.
String d = new("abc"); // d String object stored on heap again with own pointer
(c == d): false
(c.equals(d)): true
Two String pointers can point to the same String object on the heap and the direct comparison will work.
String e = d); // e String object stored on heap with d pointer
(d == e): true
(d.equals(e)): true
The equals and equalsIgnoreCase methods from String class should always be used and is good programming practice. Direct comparison of texts may introduce hard-to-find bugs.
A source of exceptions interrupting program flow is from null pointers. Eg, this fragment is better in case d holds a null pointer:
"abc".equals(d): true,
The StringComparisonTest was used to test these ideas.
public class StringComparisonTest{
public static void main(String [] args){
String a = "abc"; // text stored in string pool
String b = "abc"; // text already stored in string pool
// so just get the reference
System.out.println("String a = \"abc\"; // text stored in string pool");
System.out.println("String b = \"abc\"; // ref to text already in string pool");
System.out.println("(a == b): " + (a == b));// will be true
String c = new String("abc");// c String object stored on heap with own pointer
System.out.println("\nString c = new(\"abc\"); // c String object stored on heap with own pointer");
System.out.println("(c == b): " + (c == b));// will be false
System.out.println("(c.equals(b)): " + (c.equals(b)));// will be true
String d = new String("abc");// d String object stored on heap again with own pointer
System.out.println("\nString d = new(\"abc\"); // d String object stored on heap again with own pointer");
System.out.println("(c == d): " + (c == d));// will be false
System.out.println("(c.equals(d)): " + (c.equals(d)));// will be true
String e = d;// e String object stored on heap with d pointer
System.out.println("\nString e = d); // e String object stored on heap with d pointer");
System.out.println("(d == e): " + (d == e));// will be true as both d and e point to same String object on the heap
System.out.println("(d.equals(e)): " + (d.equals(e)));// will be true
System.out.println("\nequals method from String class better if not sure where text is stored.");
System.out.println("\"abc\".equals(d): " + ("abc".equals(d)) + ", is better in case d == null" );
}
}
This baeldung site expresses many of the above ideas more clearly.