【问题标题】:How many objects are created创建了多少对象
【发布时间】:2012-05-13 16:23:37
【问题描述】:

我正在讨论 Java 中 Strings 和 StringBuffers 的用法。这两个示例分别创建了多少个对象?

例 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 个对象。

【问题讨论】:

  • 第一个示例将创建一个对象,编译器可以对其进行优化。
  • 示例 1 生成:String s = "a"; s = (new StringBuilder(String.valueOf(s))).append("b").toString(); s = (new StringBuilder(String.valueOf(s))).append("c").toString(); System.err.println(s);。看起来 javac 没有优化(至少在 Java 6 中)
  • 如果是:“a”+“b”+“c”应该这样做。我很惊讶其他情况也没有优化。但是哦,好吧……见:nicklothian.com/blog/2005/06/09/on-java-string-concatenation
  • 第一个例子,优化?我认为所有字符串都是唯一且不可变的,所以无论优化如何,它不应该是 5 个对象吗?
  • @Thihara:如果 Javac(而不是 JIT)编译器首先进入,则不会。

标签: java string object bytecode stringbuilder


【解决方案1】:

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

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

对于Ex2,对象的最小数量是2。编译器无法知道我们是否用不同语义的自定义版本替换了StringBuilder,所以它不会优化。对于一个非常节省内存的 StringBuilder 实现,最大值可能约为 6,它一次扩展一个支持 char[] 数组一个字符,但在大多数情况下,它也将是 2。

【讨论】:

  • 编译器'为String s = "abc";'生成代码',但执行时不会创建对象,因此最小值实际上为零。
【解决方案2】:

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

在我的机器上,第一个示例创建了 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。

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

【讨论】:

  • 这台机器/编译器是否依赖?
  • @AlexLockwood:在某种程度上可能依赖于 JDK,尽管如果最近的 JDK 之间存在很大差异,我会感到非常惊讶。
  • 在Java :P 等高级语言中区分char[]String 抽象似乎相当愚蠢。但我同意这样做是正确的(对你来说并不愚蠢......只是在像这样的愚蠢例子中很愚蠢)。
  • @AlexLockwood:我实际上认为考虑子对象非常重要(例如本例中的char[]s)。没有这个,计数在很大程度上毫无意义:人们总是可以将任意数量的复杂性包装到单个对象中,并声称只有一个(顶级)new
  • @GuillaumePolet:当然char[] 是一个对象。所有Java数组都是。如果您不相信我,请尝试new char[0].getClass(),或查看stackoverflow.com/questions/2009210/…
【解决方案3】:

就创建的对象而言:

示例 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

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

【讨论】:

  • 他/她本可以在另一个JDK版本中运行测试程序并获得不同的结果。
【解决方案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."<init>":()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."<init>":()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."<init>":(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  
}

【讨论】:

  • 我有点怀疑。 , oracle docs here docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html 这样说关于 append:“public StringBuilder append(Object obj) 附加 Object 参数的字符串表示。整体效果就像通过方法 String.valueOf(对象),然后将该字符串的字符附加到此字符序列中。”这是否意味着将为字符串文字创建对象。
猜你喜欢
  • 2020-06-06
  • 2014-08-01
  • 2014-11-26
  • 2021-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-28
  • 2019-08-22
相关资源
最近更新 更多