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

我读过关于使用String s = new String("...");文章和书籍String s = new String("..."); 应该一直避免。 我理解为什么会这样,但是使用String(String)构造函数是否有任何用处? 我不认为有,也没有看到任何其他证据,但我想知道SO社区中是否有人知道有用。


精确复制: java中表达式新字符串的用途是什么?

这是一篇很好的文章: 毕竟被认为无用的字符串构造函数certificate是有用的!

事实certificate,这个构造函数实际上至少在一种情况下是有用的。 如果您曾经看过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中创建的巨大char数组的引用。 这意味着数组不会被垃圾收集,即使我们已经明确地排除了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()); 

……当然还有评论!

*我不记得在实际出现时我是否与道格拉斯合作,或者他回答这个特定问题是否巧合。

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

来自javadoc

 /** * Initializes a newly created {@code String} object so that it represents * the same sequence of characters as the argument; in other words, the * newly created string is a copy of the argument string. Unless an * explicit copy of {@code original} is needed, use of this constructor is * unnecessary since Strings are immutable. * * @param original * A {@code String} */ public String(String original){.....} 

如果您不想提供原始字符串的句柄,则需要原始字符串的副本时使用它。 但由于字符串是不可变的,我没有看到这个用例;)