2

如果我使用实例方法,在连接方面是否有任何区别 b/w 1 和 2。我的意思是在任何一种情况下,最终只会构造一个对象,即“abc”。是的,我看到的唯一区别是测试将位于 permgen 空间内,即使线程从实例方法中出来,但是一旦线程不在方法中,x 将被垃圾收集但在构造的对象数量是相同的。对?

// option 1
String test="a"+"b"+"c";

// option 2  
StringBuffer x = new StringBuffer().append("a").append("b").append("c").toString()

我参考了链接http://docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html来得出这个结论。

4

6 回答 6

8

首先请注意,您链接的文档非常旧。请注意,它适用于Java 1.4.2

J2SE 1.4.2 处于其 Java 技术生命周期终止 (EOL) 过渡期。EOL 过渡期从 2006 年 12 月 11 日开始,到 2008 年 10 月 30 日结束,届时 J2SE 1.4.2 将达到其使用寿命 (EOSL)。

较新版本的文档中,此语句已被删除。但是,添加了另一个声明,您应该注意:

从 JDK 5 开始,该类已经补充了一个为单线程使用而设计的等效类 StringBuilder。通常应该优先使用 StringBuilder 类而不是这个类,因为它支持所有相同的操作,但速度更快,因为它不执行同步。


其次请注意,您引用的文档有以下代码:

x = "a" + 4 + "c";

4不只是一个错字。您的示例不同,因为编译器会将代码转换为仅使用单个字符串文字。这两行是相同的:

x = "a" + "b" + "c"; 
x = "abc";

字符串文字将被实习。


但是在编译器不能只使用单个字符串文字的一般情况下,编译器会将第一个版本转换为第二个版本,除非它会使用StringBuilder它,因为它更有效。

于 2012-07-26T10:39:03.527 回答
5

首先 - 使用StringBuilder而不是StringBuffer,StringBuffer现在已弃用。

对于您的问题,如今这并不重要,编译器会自动将字符串连接转换为 StringBuilder。

只有两种情况可以使用它。第一个是更好的代码可读性(例如,如果您正在构建像 SQL 查询这样的长字符串)。第二个,当你在循环中连接字符串时,编译器总是为每个遍历循环创建一个新的 StringBuilder 实例,所以要小心。

于 2012-07-26T10:42:24.180 回答
4

首先,StringBuilderStringBuffer什么ArrayListVector:它应该是首选,因为它不同步。

您的第一个 String 完全在编译时构建,并存储为 String 文字。这个字面量在一个池中,test变量总是指向同一个 String 实例。

您的第二个片段在运行时动态连接三个字符串文字。每次调用它都会返回一个新的 String 实例。

于 2012-07-26T10:42:12.437 回答
4

查看 2 个示例生成的字节码,第一个字符串转换为“abc”字符串文字,而第二个调用 StringBuilder 方法。您实际上可以使用 来测试它System.out.println(test == "abc");,打印结果为 true。

   0: ldc           #2                  // String abc
   2: astore_1      
   3: new           #3                  // class java/lang/StringBuffer
   6: dup           
   7: invokespecial #4                  // Method java/lang/StringBuffer."<init>":()V
  10: ldc           #5                  // String a
  12: invokevirtual #6                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
  15: ldc           #7                  // String b
  17: invokevirtual #6                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
  20: ldc           #8                  // String c
  22: invokevirtual #6                  // Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
  25: invokevirtual #9                  // Method java/lang/StringBuffer.toString:()Ljava/lang/String;
  28: astore_2      
于 2012-07-26T10:42:36.033 回答
3

在这种特定情况下,您在编译时连接三个字符串文字,编译器将生成代码,就像您输入的一样:

String test="abc";

从而完全避免任何中间对象。

于 2012-07-26T10:42:07.170 回答
0

我认为在内存使用的情况下两者都是相同的。

于 2012-07-26T10:39:56.087 回答