在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){.....}
如果您不想提供原始字符串的句柄,则需要原始字符串的副本时使用它。 但由于字符串是不可变的,我没有看到这个用例;)
- 为什么Java Pattern类使用工厂方法而不是构造函数?
- 在java中避免使用instanceof运算符时观察多个observable?
- Spring Security 3.2.1具有不同WebSecurityConfigurerAdapters的多个登录表单
- 菜单上的java动作监听器,而不是菜单项
- 让java IAIK PKCS11包装器适用于nfast
- POJO(Plain Old Java Object)和DTO(Data Transfer Object)有什么区别?
- 设置readLine()的超时限制?
- 具有Retrofit 2的多个转换器
- 如何在Hadoop MapReduce中将Object设置为Map输出的值?