对象(和数组)上的“==”是物理上的平等。也就是说,对于对象 a 和 b,如果 a 和 b 指向同一个对象,则 a == b 为真。
编译器为您做了一些优化。例如,字符串“length”仅作为常量存储一次。因此 s1 和 s2 指向相同的(常量)字符串。
也许查看输出的字节码会有所帮助。请注意,这是从非标准 java 编译器生成的 jasmin 汇编代码。您可以通过运行“javap -c”来确认 java 编译器是否执行了类似的操作(但输出的可读性较差)。
加载对常量字符串“length”的引用并存储在 s1 中。
ldc "length"
astore_1
加载对(相同的)常量字符串“length”的引用并存储在 s2 中。
ldc "length"
astore_2
比较并打印结果。它不太可读。
getstatic java/lang/System/out Ljava/io/PrintStream;
new java/lang/StringBuffer
dup
invokespecial java/lang/StringBuffer/<init>()V
ldc "EQUAL: "
invokevirtual java/lang/StringBuffer/append(Ljava/lang/String;)Ljava/lang/StringBuffer;
aload_1
aload_2
if_acmpeq true0
iconst_0
goto end1
true0:
iconst_1
end1:
invokevirtual java/lang/StringBuffer/append(Z)Ljava/lang/StringBuffer;
invokevirtual java/lang/StringBuffer/toString()Ljava/lang/String;
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
加载“长度:10”并存储在 s3
ldc "length: 10"
astore_3
将“长度:”与长度连接并存储在 s4 中。请注意,连接将创建一个新字符串(并因此创建一个新引用)。
new java/lang/StringBuffer
dup
invokespecial java/lang/StringBuffer/<init>()V
ldc "length: "
invokevirtual java/lang/StringBuffer/append(Ljava/lang/String;)Ljava/lang/StringBuffer;
aload_3
invokevirtual java/lang/String/length()I
invokevirtual java/lang/StringBuffer/append(I)Ljava/lang/StringBuffer;
invokevirtual java/lang/StringBuffer/toString()Ljava/lang/String;
astore 4
像以前一样打印并返回。
如您所见,前两个变量指的是“常量池”中的同一个字符串。变量 s3 也指向常量池中的字符串,但 s4 指的是由常量字符串和数字构建的新字符串。
顺便说一句,你不应该依赖这种行为。