在Java中使用字符串(String)构造函数

在Java中使用字符串(String)构造函数,java,string,coding-style,Java,String,Coding Style,我在一些文章和书籍上读到,strings=newstring(“…”)应该一直避免。我理解这是为什么,但是使用字符串(String)构造函数有什么用呢?我不认为有,也看不到任何其他证据,但我想知道是否有这么一个社区的人知道使用它。如果你需要原始字符串的副本,如果你不想给原始字符串一个句柄,你可以使用它。但是,由于字符串是不可变的,所以我看不到这方面的用例;) 如果我没记错的话,唯一“有用”的情况是原始字符串是更大的后备数组的一部分。(例如,创建为子字符串)。如果您只想保留小的子字符串并对大的缓冲

我在一些文章和书籍上读到,
strings=newstring(“…”)应该一直避免。我理解这是为什么,但是使用字符串(String)构造函数有什么用呢?我不认为有,也看不到任何其他证据,但我想知道是否有这么一个社区的人知道使用它。

如果你需要原始字符串的副本,如果你不想给原始字符串一个句柄,你可以使用它。但是,由于字符串是不可变的,所以我看不到这方面的用例;)

如果我没记错的话,唯一“有用”的情况是原始字符串是更大的后备数组的一部分。(例如,创建为子字符串)。如果您只想保留小的子字符串并对大的缓冲区进行垃圾收集,那么创建一个新字符串可能是有意义的。

这是一篇好文章:

事实证明,这个构造函数实际上至少在一种情况下是有用的。如果您曾经浏览过字符串源代码,您会发现它不仅包含字符数组值和字符计数字段,还包含字符串开头的偏移量字段。这使得字符串可以与其他字符串共享char数组值,这些字符串通常是调用substring()方法之一的结果。多年前,在jwz的《Java咆哮》中,Java就因为这一点受到了著名的惩罚:

造成这种开销的唯一原因是String.substring()可以返回共享相同值数组的字符串。这样做的代价是向每个字符串对象添加8个字节,这并不是一种净节约

撇开字节节省不谈,如果您有如下代码:

// imagine a multi-megabyte string here  
String s = "0123456789012345678901234567890123456789";  
String s2 = s.substring(0, 1);  
s = null;
现在您将有一个字符串s2,尽管它看起来是一个单字符字符串,但它包含对在字符串s中创建的巨大字符数组的引用。这意味着数组不会被垃圾收集,即使我们已经显式地将字符串s置空

解决方法是使用前面提到的“无用”字符串构造函数,如下所示:

String s2 = new String(s.substring(0, 1));  
如果旧数组大于字符串中的字符数,则该构造函数实际上会将旧内容复制到新数组中,这一点并不广为人知。这意味着旧字符串内容将按预期进行垃圾收集。快乐快乐

最后,提出这些观点,

首先,字符串常量永远不会被垃圾收集。其次,字符串常量是内部的,这意味着它们在整个VM中共享。这样可以节省内存。但这并不总是你想要的

字符串上的复制构造函数允许您从字符串文本创建私有字符串实例。这对于构造有意义的互斥对象(出于同步目的)非常有价值


构造函数在很大程度上是冗余的,不建议用于一般用途。除了创建现有字符串变量的独立副本外,很少使用带字符串参数的字符串构造函数。基本上用它来“澄清”你的代码。同样如此

来自

为了扩展*,我可以举一个我在哪里使用过它的实例。考虑阅读一个字典文件,有数千行,每一个都只有一个单词。最简单的读取方法是使用
BufferedReader.readLine()

不幸的是,
readLine()
默认分配80个字符的缓冲区作为预期的行长度。这意味着它通常可以避免无意义的复制,而浪费一点内存通常也不会太糟糕。但是,如果在应用程序运行期间加载一个短词词典,那么最终会永久性地浪费大量内存。我的“小应用程序”占用的内存远远超过了它应该占用的内存

解决办法是改变这一点:

String word = reader.readLine();
为此:

String word = new String(reader.readLine());
。。。当然,有评论


*
我不记得这件事发生的时候我是否在和道格拉斯一起工作,或者他回答这个问题是否只是巧合。

这个“子字符串”或者你用来剪切它的任何东西不是已经创建了新字符串吗?不,子字符串保留了指向原始字符[]的指针而不是创建一个新的字符串(这样做速度更快,但可能会导致内存泄漏)。而且不管怎样,您并不总是能够控制创建字符串的内容-请参阅我的答案,了解一个真实的示例。更好的(IMHO)字符串实现会删除偏移量和长度。不过,您可能必须处理不太好的实现。请注意,自从Java 7(我认为)以来,这已经不再相关了,
String.substring()
的实现被更改以避免这个问题。很抱歉,我对这个技术上准确且经过充分研究的答案投了反对票,但时间已经让它变得不那么相关了(基本上只是从历史的角度来看很有趣,但不再适用于当前的JVM)。
String word = new String(reader.readLine());