オブジェクト(および配列)の「==」は物理的な同等性です。つまり、オブジェクトaとbの場合、aとbが同じオブジェクトを指している場合、a==bは真です。
コンパイラはあなたのためにいくつかの最適化を行います。たとえば、文字列「length」は定数として1回だけ保存されます。したがって、s1とs2は同じ(定数)文字列を指します。
おそらく、出力されたバイトコードを確認するのに役立ちます。これは、非標準のJavaコンパイラから生成されたjasminアセンブリコードであることに注意してください。「javap-c」を実行することで、Javaコンパイラが同様のことを行うことを確認できます(ただし、出力は読みにくくなります)。
定数文字列「長さ」への参照をロードし、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
「length:」を長さと連結し、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
前と同じように印刷して戻ります。
ご覧のとおり、最初の2つの変数は、「定数プール」内の同じ文字列を参照しています。変数s3も定数プール内の文字列を参照していますが、s4は定数文字列と数値から作成された新しい文字列を参照しています。
ところで、この動作に依存するべきではありません。