Java字符串常量池 – 创建的对象数

以下代码将创建多少个字符串对象?

String s = "Mahendra" + "Singh" + "Dhoni"; 

它会在字符串池中创建4个字符串对象还是会创建更多? 请详细解释。

PS我见过其他例子,他们只处理2个字符串对象。

编辑:我从答案中看到,在上面的情况下,只会创建一个对象。 非常感谢一些非常好的建议。 很抱歉问一个愚蠢的问题,但是你可以在下面的例子中说明将创建多少个对象?

 String s = "Mahendra"; s = s + "Singh" + "Dhoni"; 

第二次编辑:再次抱歉,但我还有一些疑问。 我在评论中看到,在上面的例子中,将创建3个对象“Mahendra”,“SinghDhoni”和“MahendraSinghDhoni”。 我怀疑不应该从左到右计算。 我错过了什么 – 概念明智吗? 请帮忙。

另外,在另一种情况下,如果我扭曲这个问题,对象的数量将如何变化。 我正在详细询问这一点,以便为很多同事清除它。 所有的帮助表示赞赏。

 String s = "Singh"; s = "Mahendra" + s + "Dhoni"; 

如果您的代码是:

 public static void main(String[] args) { String s = "Mahendra" + "Singh" + "Dhoni"; System.out.println(s); } 

看一下字节码:

  public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: ldc #16 // String MahendraSinghDhoni --> This line 2: astore_1 3: getstatic #18 // Field java/lang/System.out:Ljav /io/PrintStream; 6: aload_1 7: invokevirtual #24 // Method java/io/PrintStream.prin ln:(Ljava/lang/String;)V 10: return 

如您所见,编译器在编译期间添加了所有三个字符串。 所以String常量池上 只有一个字符串

编辑:根据编辑的问题:

编译期间将添加"Singh" + "Dhoni" 。 所以总共会有3个String对象。 "Mahendra""SinghDhoni"将在String常量池上 ,然后mahendraSinghDhoni将在堆上

这将在字符串池中仅创建1个字符串。 请阅读差异bwt String对象和文字它将帮助您理解。

这是编译器进行优化的特殊条件。 不同的编译器可以进行不同的优化。 以下是可能发生的事情:

方案1

编译器查看已知值的字符串连接。 如果值未在其他位置使用,则可以使用最终字符串替换串联

 String concatenation = "a" + "b" + "c"; 

被编译为等效的字节码

 String concatenation = "abc"; 

在这种情况下,您将只创建一个字符串。

方案2

在一定数量的字符串连接上,编译器可以决定用StringBuilderStringBuffer替换它们。 所以

 String a; String b; String c; String d; String e; // Initialization and use of a, b, c, d, e String concat = a + b + c + d + e; 

被编译为以下java代码的等效字节码:

 String a; String b; String c; String d; String e; // Initialization and use of a, b, c, d, e String concat = new StringBuilder(a).append(b).append(c).append(d).append(e).toString(); 

在这种情况下,您将创建6个字符串:a,b,c,d,e,以及从+ b + c + d + e获得的字符串

方案3

如果StringBuilder的创建不方便,编译器可以应用正常的字符串连接,以便下面的代码

 String a; String b; String c; // Initialization and use of a, b, c String concat = a + b + c; 

被编译为等效于以下java代码的字节码

 String a; String b; String c; // Initialization and use of a, b, c String concat = a.concat(b).concat(c); 

这是concat代码的java实现:

 public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } char buf[] = new char[count + otherLen]; getChars(0, count, buf, 0); str.getChars(0, otherLen, buf, count); return new String(0, count + otherLen, buf); } 

正如您在concat的最后一行所看到的,为每个连接创建了一个新的String。 在这种情况下,您将创建5个字符串:a,b,c,a + b和a + b + c

注意:任何不同的编译器都可以选择从源代码到编译代码的不同内部优化。 您需要知道的是,在最坏的情况下,每个起始字符串将生成1个字符串,每个连接将生成1个字符串(每个+)。 因此,如果您有3个字符串与2个连接操作连接,则最多可创建5个字符串。