题主你只要知道有个叫常量池的东西就行了,类似String a = "helloworld"里的helloworld在虚拟节规范中叫字面量,不管你定义多少="helloworld"的变量,都是指向的同一个地址。
你的例子还可以稍微改一下:
String a = "hello";
String b = "world";
String ab = "helloworld";
System.out.println(ab==(a+b).intern());
这样的话也是返回true,这里intern的地址实际上就是常量池上的地址。
如果从反编译后的字节码看也能得出true的结论:
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=5, locals=4, args_size=1
0: ldc #16 // String hello
2: astore_1
3: ldc #18 // String world
5: astore_2
6: ldc #20 // String helloworld
8: astore_3
9: getstatic #22 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_3
13: new #28 // class java/lang/StringBuilder
16: dup
17: aload_1
18: invokestatic #30 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
21: invokespecial #36 // Method java/lang/StringBuilder."":(Ljava/lang/String;)V
24: aload_2
25: invokevirtual #39 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #43 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: if_acmpne 38
34: iconst_1
35: goto 39
38: iconst_0
39: invokevirtual #47 // Method java/io/PrintStream.println:(Z)V
42: getstatic #22 // Field java/lang/System.out:Ljava/io/PrintStream;
45: aload_3
46: ldc #20 // String helloworld
48: if_acmpne 55
注意我标粗的四行,6和8实际就是String ab = "helloworld",注意这个#20是指常量池的第20项,我把它贴出来:
#20 = String #21 // helloworld
#21 = Utf8 helloworld
实际上就是一个Utf8的字符串。
然后看45,把本地变量3压栈(这里本地变量3就是ab),ldc常量池第20项压栈,(对照着6和8来看)实际上这俩就是同一个东西。