Java 字符串是不可变的-这意味着我永远不应该使用+;=只有StringBuffer?
字符串是不可变的,这意味着,一旦创建了字符串,就不能对其进行更改 那么,这是否意味着如果使用+=附加内容,会比创建一个StringBuffer并向其附加文本需要更多内存Java 字符串是不可变的-这意味着我永远不应该使用+;=只有StringBuffer?,java,string,immutability,stringbuilder,stringbuffer,Java,String,Immutability,Stringbuilder,Stringbuffer,字符串是不可变的,这意味着,一旦创建了字符串,就不能对其进行更改 那么,这是否意味着如果使用+=附加内容,会比创建一个StringBuffer并向其附加文本需要更多内存 如果你使用+=,你每次都会创建一个新的“对象”,它必须保存在内存中,不是吗 是的。字符串是不可变的。对于偶尔使用,+=是可以的。如果+=操作是密集型的,您应该求助于StringBuilder。我认为它依赖GC来收集包含废弃字符串的内存。 因此,如果您对字符串操作有很多操作,那么使用字符串生成器执行+=肯定会更快。但在大多数情况下
如果你使用+=,你每次都会创建一个新的“对象”,它必须保存在内存中,不是吗 是的。字符串是不可变的。对于偶尔使用,+=是可以的。如果+=操作是密集型的,您应该求助于StringBuilder。我认为它依赖GC来收集包含废弃字符串的内存。
因此,如果您对字符串操作有很多操作,那么使用字符串生成器执行+=肯定会更快。但在大多数情况下,这应该不是问题。没错。如果线程安全不是问题,那么应该使用StringBuilder 作为旁注:可能有几个字符串对象使用相同的backing char[]——例如,每当使用substring(),都不会创建新的char[],这使得使用它非常有效 此外,编译器可能会为您进行一些优化。例如,如果你这样做
static final String FOO = "foo";
static final String BAR = "bar";
String getFoobar() {
return FOO + BAR; // no string concatenation at runtime
}
如果编译器在可能的情况下在内部使用StringBuilder来优化字符串连接,我也不会感到惊讶,如果将来还没有的话。是的,你会这样做,这就是为什么你应该使用StringBuffer来连接很多字符串
还要注意的是,由于Java5,大多数时候您也应该更喜欢StringBuilder。它只是某种不同步的StringBuffer。但是垃圾收集器将在Java 5或更高版本中没有对旧字符串的引用时释放这些字符串,StringBuffer是线程安全的,因此有一些开销,除非您需要,否则您不应该为此付费。StringBuilder具有相同的API,但不是线程安全的(即,您应该只在单个线程内部使用它)
是的,如果您正在构建大型字符串,则使用StringBuilder更有效。作为API的一部分传递StringBuilder或StringBuffer可能不值得。这太令人困惑了。是的,您每次都将使用+=,创建一个新对象。然而,这并不意味着它总是错误的。这取决于您是希望将该值作为字符串,还是只想使用它进一步构建字符串 如果您确实希望将
x+y
的结果作为字符串,那么您也可以使用字符串串联。但是,如果您真的要(比如)循环并附加另一个字符串,以及另一个字符串,等等-只需要在最后将结果作为一个字符串,那么StringBuffer/StringBuilder就是最好的选择。事实上,循环是StringBuilder比字符串连接更有效的地方——5次甚至10次直接连接的性能差异将非常小,但对于数千次直接连接来说,性能差得多——基本上是因为连接的复杂度为O(N2),而StringBuilder的复杂度为O(N)
在Java5和更高版本中,基本上应该使用StringBuilder——它是不同步的,但这几乎总是可以的;想要在线程之间共享一个线程是非常罕见的
我有一个你可能会觉得有用的方法。经验法则很简单: 如果在循环中运行串联,请不要使用
+=
如果您不是在循环中运行串联,那么使用
+=
根本不重要。(除非性能关键型应用程序认为字符串是不可变的,否则您是对的,因此如果您在执行大量字符串连接时试图节省内存,则应使用StringBuilder而不是+=
但是,您可能不介意。程序是为其人类读者编写的,因此您可以清晰地阅读。如果优化很重要,您应该首先进行分析。除非您的程序非常重视字符串活动,否则可能会有其他瓶颈。我同意上面发布的所有答案,但这会对您有所帮助您需要稍微了解一下Java的实现方式。JVM在内部使用StringBuffers来编译String+运算符(从中): 字符串缓冲区由 编译器来实现二进制代码 字符串串联运算符+。用于 例如,代码:
x = "a" + 4 + "c"
编译为等效于:
x = new StringBuffer().append("a").append(4).append("c")
.toString()
同样地,x+=“somenewstring”
相当于x=x+“somenewstring”
。你明白我的意思了吗
如果要进行大量的字符串连接,使用StringBuffer将提高性能,但是如果只进行几个简单的字符串连接,Java编译器可能会为您进行优化,并且您不会注意到性能上的差异否
它不会占用更多内存。是的,会创建新对象,但会回收旧对象。最终,使用的内存量是相同的。StringBuffer一直都是同步的-他们没有让它在Java 5中同步,这就是他们引入StringBuilder的原因。这比我以前认为的更有意义。我不知道ced注意到文档从1.4更改为5,现在更突出地提到了线程安全。当您执行大量字符串操作时,No+=不会更快,StringBuffer会更快。您对GC的看法是正确的,它可能会正确地处理所有废弃的字符串对象,但仍然存在创建对象的成本ion..问题不在于垃圾本身。杀死你的是所有的字符复制!使用
+=
copiesO(N^2)将N个字符串接为1个字符串
characters。我不太确定。一些字符串会在Perm空间中结束,据我所知,该区域没有垃圾收集器。字符串对象通过使用string.intern()进入池。如果您在string
上调用intern()
,则