在Java中如何复制字符串?

235
    String s = "hello";
    String backup_of_s = s;
    s = "bye";

此时,备份变量仍然包含原始值“hello”(这是由于String的不可变性吗?)。

但是使用这种方法复制字符串是否真的“安全”(这是因为通常不能安全地复制可变对象),还是最好写成这样:

    String s = "hello";
    String backup_of_s = new String(s);
    s = "bye";

换句话说,这两个片段有什么区别(如果有的话)?


编辑 - 第一个片段为什么是安全的原因:

让我用更详细的方式解释一下,基于已经提供的好答案(它们基本上专注于2个片段之间的性能差异问题):

在Java中,字符串是不可变的,这意味着一个String对象在构建完成后就不能被修改了。 因此,

String s = "hello"; 创建一个新的String实例,并把它的地址赋给s(s是指向该实例/对象的引用)

String backup_of_s = s; 创建一个新变量backup_of_s,并初始化它,使其引用当前由s引用的对象。

注意:String的不可变性保证该对象不会被修改:我们的备份是安全的

注意2:Java垃圾回收机制保证只要该对象被至少一个变量引用(在这种情况下是backup_of_s),它就不会被销毁

最后,s = "bye"; 创建另一个String实例(由于不可变性,这是唯一的方法),并修改s变量,使其现在引用新的对象。

5个回答

166

由于字符串是不可变的,因此两个版本都是安全的。然而,后者不够高效(它会创建一个额外的对象,并且在某些情况下会复制字符数据)。

考虑到这一点,应该优先选择第一种版本。


23
不需要考虑不可变性。这只是对象引用的工作方式而已。我可以提供一个等效的StringBuilder示例。 - GriffeyDog
2
@BalusC,我不明白new String()如何在JVM的字符串池中创建任何内容。只有字符串字面量和通过intern()提交到池中的字符串才在池中。 - Snicolas
3
@GriffeyDog说:“我并不是按照字面意思来理解问题。我的意思是,可以放心地提供字符串对象的引用,不必担心有人会修改该字符串。” - NPE
3
我觉得你的评论很误导人:不可变性是使第一个片段安全的原因,你为什么说它与 "它" 没有任何关系? - Sébastien
5
它所做的只是重新分配引用变量s来引用不同的对象(即字符串“bye”)。 这不影响引用变量backup_of_s所引用的内容(即字符串“hello”)。就像我说的,我可以提供一个使用StringBuilder(它们不是不可变的)的等效示例。 我的评论主要与OP的陈述有关:“此时,备份变量仍包含原始值“hello”(这是因为String是不可变的吗?)。" - GriffeyDog
显示剩余3条评论

28

字符串是不可变对象,因此您可以通过仅复制对它们的引用来复制它们,因为被引用的对象无法更改...

因此,您可以像第一个示例中那样进行复制,没有任何问题:

String s = "hello";
String backup_of_s = s;
s = "bye";

10
你的第二个版本不够高效,因为在没有必要的情况下创建了一个额外的字符串对象。
不可变性意味着你的第一个版本表现出符合预期的行为,因此应该优先选择这种方式。

0

第二种情况在字符串池方面也是低效的,您必须显式调用intern()来使返回引用变为内部对象。


-14
String str1="this is a string";
String str2=str1.clone();

这样复制怎么样? 我认为获取一个新的副本更好,这样当str2被引用并在后续操作中被修改时,str1的数据不会受到影响。


4
String 是不可变的。复制字符串没有太多意义。 - Vladimir
2
在特定的上下文中,如果您想比较对象和引用,它就有用了... - Pipo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接