一看指令码,这不是在循环里(if_icmpgt)给我 new 了 StringBuilder 了吗,怎么还这么慢呢?再仔细看,其实你会发现,这new是在循环里吗呀,我们把这段代码写出来再看看;
String str ="";for(int i =0; i <10000; i++){
str =newStringBuilder().append(str).append(i).toString();}
现在再看这段代码就很清晰了,所有的字符串链接操作,都需要实例化一次StringBuilder,所以非常耗时。并且你可以验证,这样写代码耗时与字符串直接链接是一样的。 所以把StringBuilder 提到上一层 for 循环外更快。
四、String 源码分析
publicfinalclassStringimplementsjava.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */privatefinalchar value[];/** Cache the hash code for the string */privateint hash;// Default to 0/** use serialVersionUID from JDK 1.0.2 for interoperability */privatestaticfinallong serialVersionUID =-6849794470754667710L;...}
/**
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
* class {@code String}.
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
* <p>
* It follows that for any two strings {@code s} and {@code t},
* {@code s.intern() == t.intern()} is {@code true}
* if and only if {@code s.equals(t)} is {@code true}.
* <p>
* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
* <cite>The Java™ Language Specification</cite>.
*
* @return a string that has the same contents as this string, but is
* guaranteed to be from a pool of unique strings.
*/publicnative String intern();
这段代码和注释什么意思呢?
native,说明 intern() 是一个本地方法,底层通过JNI调用C++语言编写的功能。
\openjdk8\jdk\src\share\native\java\lang\String.c
Java_java_lang_String_intern(JNIEnv *env, jobject this)
{
return JVM_InternString(env, this);
}
oop result = StringTable::intern(string, CHECK_NULL);
oop StringTable::intern(Handle string_or_null, jchar* name,
int len, TRAPS) {
unsigned int hashValue = java_lang_String::hash_string(name, len);
int index = the_table()->hash_to_index(hashValue);
oop string = the_table()->lookup(index, name, len, hashValue);
if (string != NULL) return string;
return the_table()->basic_add(index, string_or_null, name, len,
hashValue, CHECK_NULL);
}
public AbstractStringBuilder append(String str){if(str == null)returnappendNull();int len = str.length();ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;returnthis;}
这个是 public final class StringBuilder extends AbstractStringBuilder,的父类与 StringBuffer 共用这个方法。
这里包括了容量检测、元素拷贝、记录 count 数量。
2.2 扩容操作
ensureCapacityInternal(count + len);
/**
* This method has the same contract as ensureCapacity, but is
* never synchronized.
*/privatevoidensureCapacityInternal(int minimumCapacity){// overflow-conscious codeif(minimumCapacity - value.length >0)expandCapacity(minimumCapacity);}/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.
*/voidexpandCapacity(int minimumCapacity){int newCapacity = value.length *2+2;if(newCapacity - minimumCapacity <0)
newCapacity = minimumCapacity;if(newCapacity <0){if(minimumCapacity <0)// overflowthrownewOutOfMemoryError();
newCapacity = Integer.MAX_VALUE;}
value = Arrays.copyOf(value, newCapacity);}
如上,StringBuilder,就跟操作数组的原理一样,都需要检测容量大小,按需扩容。扩容的容量是 n * 2 + 2,另外把原有元素拷贝到新新数组中。