@Pritam Banerjee's answer is not fully correct.
// both declarations are using the same object in memory
String s1 = "ABC:5"; // s1 == s1
String s2 = "ABC:5"; // s2 == s1
// this one creates at the beginning StringBuilder
String s3 = "ABC:" + s1.length(); // s3 != s1
String s4 = new StringBuilder().append("ABC:").append(s1.length()).toString();
// s4 != s1 && s4 != s3 this is what happens in byte code for s3
// the last case
String s5 = "ABC:" + "5"; // s5 == s1, because compiler knows exact value before compiling
The byte code for it:
public StringBuilderTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String ABC:5
2: astore_1
3: ldc #2 // String ABC:5
5: astore_2
6: new #3 // class java/lang/StringBuilder
9: dup
10: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
13: ldc #5 // String ABC:
15: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
18: aload_1
19: invokevirtual #7 // Method java/lang/String.length:()I
22: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
25: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
28: astore_3
29: new #3 // class java/lang/StringBuilder
32: dup
33: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
36: ldc #5 // String ABC:
38: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/Stri
ngBuilder;
41: aload_1
42: invokevirtual #7 // Method java/lang/String.length:()I
45: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
48: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
51: astore 4
53: ldc #2 // String ABC:5
55: astore 5
57: return
}
You can read more about declaring Strings and its equality here