可能重复:
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) {
....
....}
答案 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)
当旧的行为证明它是正当的时候。