复制字符串的主要原因是“修剪包袱”,即将底层 char 数组修剪为只需要的部分。
底层的 char 数组可能太大,主要是因为当你通过调用创建字符串时substring
,char 数组可以在新的字符串实例和源字符串实例之间共享;偏移量指向第一个字符并包含长度。
我使用的表达式“trim the bag”取自 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 不是垃圾收集内存。许多开发人员认为,Java 设计人员决定使用这种 C 编码人员熟悉的旧优化技巧实际上弊大于利。我们中的许多人都知道它,因为我们被它咬住了,并且确实不得不查看 Sun 的源代码以了解发生了什么......
正如 Marko 指出的那样(见下面的评论),在 OpenJDK 中,从 java 7 Update 6 开始,substring
不再共享 char 数组String(String)
,因此构造函数是无用的。但它仍然很快(实际上甚至更快),并且由于此更改尚未传播到所有 VM(可能不是您的所有客户),我建议new String(substring)
在旧行为证明其合理性时保留此最佳实践。