为什么String类有复制构造函数?

Pra*_*eek 13 java

可能重复:
Java中表达式"new String(...)"的目的是什么?

如果不可变类对象副本将等于原始副本那么为什么StringJava 中的类具有复制构造函数?这是一个错误还是这个实施背后的原因?在Java文档中,它被指定为:

/**
 * 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) {
 ....
 ....}
Run Code Online (Sandbox Code Playgroud)

Den*_*ret 10

复制字符串的主要原因是"修剪行李",即将基础字符数组修剪为仅需要的内容.

底层char数组可能过大,因为在通过调用创建字符串时substring,char数组可以在新字符串实例和源字符串实例之间共享; 偏移量指向第一个字符,并包含长度.

我使用的表达式"修剪行李"取自String复制构造函数的源代码:

  164       public String(String original) {
  165           int size = original.count;
  166           char[] originalValue = original.value;
  167           char[] v;
  168           if (originalValue.length > size) {
  169               // The array representing the String is bigger than the new
  170               // String itself.  Perhaps this constructor is being called
  171               // in order to trim the baggage, so make a copy of the array.
  172               int off = original.offset;
  173               v = Arrays.copyOfRange(originalValue, off, off+size);
  174           } else {
  175               // The array representing the String is the same
  176               // size as the String, so no point in making a copy.
  177               v = originalValue;
  178           }
  179           this.offset = 0;
  180           this.count = size;
  181           this.value = v;
Run Code Online (Sandbox Code Playgroud)

这是许多开发人员忘记并且很重要的事情,因为一个小字符串可能会阻止更大的char数组的吞噬.看到这个相关的问题,我已经指出了这一点:Java不是垃圾收集内存.许多开发人员认为,而不是Java设计者决定使用C编码器所熟悉的旧优化技巧,实际上弊大于利.我们中的许多人都知道它,因为我们被它咬了,并且必须查看Sun的源代码以了解发生了什么......

正如Marko指出的那样(见下面的评论),在OpenJDK中,从java 7 Update 6开始,substring不再共享char数组String(String),因此构造函数是无用的.但它仍然很快(事实上更快)并且由于这种变化没有传播到所有VM(可能不是所有客户),我建议保持这种最佳实践,以便new String(substring)在旧行为证明其合理性时使用.

  • ...它从OpenJDK 7,Update 6开始消失了.通过`substring`,`trim`等没有更多的结构共享. (5认同)
  • [这里的参考](http://hg.openjdk.java.net/jdk7u/jdk7u6/jdk/file/8c2c5d63a17e/src/share/classes/java/lang/String.java)我已经把它加了书签,它已被自从我从Jon Skeet那里了解到它以来,在大众的需求中! (3认同)