2

可能重复:
关于 Java 字符串池的问题

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 // 为什么?

4

3 回答 3

4
 String s4 = "length: " + s3.length();

创建新的字符串对象。

因此, s3 引用不同的对象, s4 引用不同的对象,这使得==条件返回false

于 2012-10-02T14:47:15.227 回答
1

没有“新”运算符。所以所有东西都必须在常量池中创建,不能有重复值?

String s4 = "length: " + s3.length();

String s4 = new StringBuilder().append("length: ")
                               .append(Integer.toString(s3.length()))
                               .toString();

所以它创建了很多新对象和一个新字符串。

于 2012-10-02T14:57:12.133 回答
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

将“长度:”与长度连接并存储在 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 指的是由常量字符串和数字构建的新字符串。

顺便说一句,你不应该依赖这种行为。

于 2012-10-02T15:14:56.050 回答