创建了多少个对象

我正在讨论在Java中使用StringStringBuffer的问题。 这两个例子中每个都创建了多少个对象?

例1:

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

例2:

 StringBuilder sb = new StringBuilder("a"); sb.append("b"); sb.append("c"); 

在我看来,Ex 1将创建5,而Ex 2将创建4个对象。

您可以通过分析java字节码来确定答案(使用javap -c )。 示例1创建了两个StringBuilder对象(参见第4行)和两个String对象(参见第7行),而示例2创建了一个StringBuilder对象(参见第2行)。

请注意,您还必须考虑char[]对象(因为数组是Java中的对象)。 StringStringBuilder对象都使用底层char[] 。 因此,示例1创建了八个对象,示例2创建了两个对象。

例1:

 public static void main(java.lang.String[]); Code: 0: ldc #2; //String a 2: astore_1 3: new #3; //class java/lang/StringBuilder 6: dup 7: invokespecial #4; //Method java/lang/StringBuilder."":()V 10: aload_1 11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: ldc #6; //String b 16: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 19: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 22: astore_1 23: new #3; //class java/lang/StringBuilder 26: dup 27: invokespecial #4; //Method java/lang/StringBuilder."":()V 30: aload_1 31: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 34: ldc #8; //String c 36: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 39: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 42: astore_1 43: return } 

例2:

 public static void main(java.lang.String[]); Code: 0: new #2; //class java/lang/StringBuilder 3: dup 4: ldc #3; //String a 6: invokespecial #4; //Method java/lang/StringBuilder."":(Ljava/lang/String;)V 9: astore_1 10: aload_1 11: ldc #5; //String b 13: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 16: pop 17: aload_1 18: ldc #7; //String c 20: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 23: pop 24: return } 

我使用了内存分析器来获取确切的计数。

在我的机器上,第一个示例创建了8个对象:

 String s = "a"; s = s + "b"; s = s + "c"; 
  • 两个String类型的对象;
  • StringBuilder类型的两个对象;
  • char[]类型的四个对象。

另一方面,第二个例子:

 StringBuffer sb = new StringBuffer("a"); sb.append("b"); sb.append("c"); 

创建2个对象:

  • StringBuilder类型的一个对象;
  • char[]类型的一个对象。

这是使用JDK 1.6u30。

PS为了使比较公平,您可能应该在第二个示例的末尾调用sb.toString()

在创建的对象方面:

示例1创建了8个对象:

 String s = "a"; // No object created s = s + "b"; // 1 StringBuilder/StringBuffer + 1 String + 2 char[] (1 for SB and 1 for String) s = s + "c"; // 1 StringBuilder/StringBuffer + 1 String + 2 char[] (1 for SB and 1 for String) 

示例2创建了2个对象:

 StringBuffer sb = new StringBuffer("a"); // 1 StringBuffer + 1 char[] (in SB) sb.append("b"); // 0 sb.append("c"); // 0 

公平地说,我不知道新的char []实际上是用Java创建了一个Object(但我知道它们是创建的)。 感谢aix指出了这一点。

答案与语言的特定实现(编译器和运行时库)有关。 甚至是否存在特定的优化选项。 当然还有实现的版本(并且,隐含地,它是符合的JLS)。 所以,最好用最小值和最大值来说话。 事实上,这个练习提供了更好的

对于Ex1,最小对象数为1(编译器意识到只涉及常量并仅生成String s= "abc" ; )的代码。 最大可能是任何东西,取决于实现,但合理的估计是8(在另一个答案中也给出了某些配置产生的数字)。

对于Ex2,最小对象数为2.编译器无法知道我们是否已将StringBuilder替换为具有不同语义的自定义版本,因此不会进行优化。 对于一个极其节省内存的StringBuilder实现,最大可能是6左右,它一次扩展一个char[]的后备char[]数组,但在大多数情况下它也是2。