String s1 = "length";
String s2 = "length";
System.out.println("EQUAL: " + (s1 == s2));
String s3 = "length: 10";
String s4 = "length: " + s3.length();
System.out.println(s3.length());
System.out.println(s4.length());
System.out.println("EQUAL: " + (s3 == s4));
输出:
EQUAL:true //在字符串池中理解相同的字符串引用
10
10
EQUAL:false //为什么?
答案 0 :(得分:4)
String s4 = "length: " + s3.length();
创建新的String对象。
因此,s3引用不同的对象,s4引用不同的对象,这使得==
条件返回false
。
答案 1 :(得分:1)
没有新的'运营商。所以一切都必须在常量池中创建,它不能有重复的值?
String s4 = "length: " + s3.length();
与
大致相同String s4 = new StringBuilder().append("length: ")
.append(Integer.toString(s3.length()))
.toString();
因此它会创建相当多的新对象和一个新的String。
答案 2 :(得分:1)
“==”是物理上的相等。也就是说,对于对象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
将“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
像以前一样打印并返回。
如您所见,前两个变量引用“常量池”中的相同字符串。变量s3也指常量池中的字符串,但s4指的是从常量字符串和数字构建的新字符串。
不过,你不应该依赖这种行为。