Java字符串:常量池

时间:2012-10-02 14:46:26

标签: java

  

可能重复:
  Questions about Java's String pool

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

3 个答案:

答案 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指的是从常量字符串和数字构建的新字符串。

不过,你不应该依赖这种行为。