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

时间:2012-12-10 15:04:00

标签: java

  

可能重复:
  What is the purpose of the expression “new String(…)” in Java?

如果不可变类对象副本等于原始副本那么为什么Java中的String类具有复制构造函数?这是一个错误还是这个实施背后的原因? 在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) {
 ....
 ....}

1 个答案:

答案 0 :(得分: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;

这是许多开发人员忘记并且很重要的事情,因为一个小字符串可能会阻止更大的char数组的冒泡。请参阅此相关问题,我已在此处指出:Java not garbage collecting memory。许多开发人员认为,而不是Java设计者决定使用C编码器所熟悉的旧优化技巧,实际上弊大于利。我们中的许多人都知道它,因为我们被它咬了,并且必须查看Sun的源代码才能理解发生了什么......

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