我读过文章和书籍,String s = new String("...");
应该尽可能避免使用.我明白为什么会这样,但是使用String(String)构造函数有什么用处吗?我不认为有,也没有看到任何其他证据,但我想知道SO社区中是否有人知道有用.
确切重复: java中表达新字符串的目的是什么?
这是一篇很好的文章:毕竟认为无用的字符串构造函数毕竟是有用的!
事实证明,这个构造函数实际上至少在一种情况下是有用的.如果你曾经看过String源代码,你会发现它不仅包含char数组值和字符数的字段,而且还包含字符串开头的偏移量.这样,Strings可以与其他字符串共享char数组值,通常是调用substring()方法之一.Java在几年前的jwz'Java咆哮中受到了严厉的批评:
这种开销的唯一原因是String.substring()可以返回共享相同值数组的字符串.这样做是为了向每个String对象添加8个字节而不是净节省......
除了节省字节,如果你有这样的代码:
// imagine a multi-megabyte string here String s = "0123456789012345678901234567890123456789"; String s2 = s.substring(0, 1); s = null;你现在将拥有一个String s2,虽然它似乎是一个单字符的字符串,但它拥有对String中创建的巨大字符数组的引用.这意味着数组不会被垃圾收集,即使我们已经明确地删除了String!
解决这个问题的方法是使用我们之前提到的"无用的"String构造函数,如下所示:
String s2 = new String(s.substring(0, 1));众所周知,如果旧数组大于字符串中的字符数,则此构造函数实际上将旧内容复制到新数组.这意味着旧的String内容将按预期进行垃圾回收.快乐幸福快乐的喜悦.
最后,Kat Marsen提出了这些观点,
首先,字符串常量永远不会被垃圾收集.其次,字符串常量是实习的,这意味着它们在整个VM中共享.这节省了内存.但它并不总是你想要的.
String上的复制构造函数允许您从String文本创建私有String实例.这对于构造有意义的互斥对象(出于同步目的)非常有价值.
如果我没记错的话,唯一"有用"的情况是原始字符串是更大的后备数组的一部分.(例如,创建为子字符串).如果你只想保留小的子串并且垃圾收集大缓冲区,那么创建一个新的String可能是有意义的.
为了扩展道格拉斯的答案*,我可以给出一个我用过它的确凿例子.考虑阅读一个包含数千行的字典文件,每个行只有一个单词.阅读本文的最简单方法是使用BufferedReader.readLine()
.
不幸的是,readLine()
默认情况下,分配一个80个字符的缓冲区作为预期的行长度.这意味着它通常可以避免无意义的复制 - 而且浪费的内存通常不会太糟糕.但是,如果您在应用程序的持续时间内加载了一个短词字典,那么最终会浪费大量内存.我的"小应用程序"吸取的内存远远超过应有的内存.
解决方案是改变这个:
String word = reader.readLine();
进入这个:
String word = new String(reader.readLine());
......当然还有评论!
*
我不记得在实际出现这个问题时我是否与道格拉斯合作,或者他回答这个问题是否巧合.