【问题标题】:Why String class has copy constructor? [duplicate]为什么 String 类有复制构造函数? [复制]
【发布时间】:2012-11-28 00:24:43
【问题描述】:

可能重复:
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) {
 ....
 ....}

【问题讨论】:

  • 这不是“过于本地化”,这是一个很好的问题,适用于后来发现它的人,答案非常有用且内容丰富。
  • this 回答。
  • 请注意,上述类似问题的答案现在可能被认为已部分过时。

标签: java


【解决方案1】:

复制字符串的主要原因是“修剪包袱”,即将底层的char数组修剪成只需要的部分。

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

我使用的表达式,“trim the bag”,取自字符串复制构造函数的源代码:

  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 指出的(参见下面的 cmets),在 OpenJDK 中,从 java 7 Update 6 开始,substring 不再共享 char 数组,因此 String(String) 构造函数是无用的。但它仍然很快(实际上甚至更快),并且由于此更改尚未传播到所有 VM(可能不是您的所有客户),我建议在旧行为是时保持此最佳实践以使用 new String(substring)证明它的合理性。

【讨论】:

  • ...它从 OpenJDK 7 更新 6 中消失了。不再通过substringtrim 等进行结构共享。
  • @Marko 你能指出你提到的更新的来源吗?我不知道这个重要的变化。
  • Reference over here我已经把它加入书签了,自从我从 Jon Skeet 那里得知它后,它就一直很受欢迎!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-24
  • 1970-01-01
  • 2012-02-28
  • 1970-01-01
  • 2014-05-18
  • 2013-11-25
  • 1970-01-01
相关资源
最近更新 更多