1.类结构
String Diagrams
StringBuffer Diagrams
StringBuilder Diagrams
通过以上Diagrams可以看出,String,StringBuffer,StringBuilder都是CharSequence的实现类,其中StringBuffer,StringBuilder都是AbstractStringBuilder的子类
2.源码分析
a>String
通过String的API可以看出String类中没有像StringBuffer和StringBuilder类对字符串进行append/insert/delete操作,当然我们可以通过str1+str2的方式对String对象进行改变,但是这种方式的改变,不但String对象值改变了,而且对象也改变了.我们可以通过下面代码进行验证
1 public static void main(String[] args) throws Exception{ 2 String str = new String("string"); 3 System.out.println(str.hashCode()); //输出:-891985903 4 str += "123"; 5 System.out.println(str.hashCode()); //输出:-189327231 6 }
通过StringBuffer,StringBuilder源码分析可以推测(代码第4行)实现过程:
String源码关键变量:
str += "123"代码实现:
1 public static void main(String[] args) throws Exception{ 2 Charset charset = Charset.forName("utf-8"); 3 /** 4 * String str = new String("string"); 5 * 相当于初始化String对象过程中private final char value[]; 6 * 即valuestring=value 7 */ 8 char[] valuestring = charset.decode(charset.encode("string")).array(); 9 /** 10 * 初始化String对象 "123" 11 * 相当于初始化String对象过程中private final char value[]; 12 * 即valuestring=value 13 */ 14 char[] value1123 = charset.decode(charset.encode("123")).array(); 15 16 /** 17 * str += "123" 结果对象的 private final char value[]; 18 */ 19 char[] valuecopy = new char[9]; 20 21 /** 22 * 相当于字符串拼接过程 23 * 即新建一个char数组valuecopy,用来存储valuestring,value1123 24 */ 25 System.arraycopy(valuestring,0,valuecopy,0,valuestring.length); 26 System.arraycopy(value1123,0,valuecopy,valuestring.length,value1123.length); 27 28 System.out.println(new String(valuecopy));//输出:string123 29 30 }
通过查看源码我们发现System.arraycopy是本地方法,即调用的C语言实现的方法
1 public static native void arraycopy(Object src, int srcPos, 2 Object dest, int destPos, 3 int length);
不过我们通过jdk-api知道是数组的拷贝,我们可以想象下,每次扩展String对象值,都需要新建数组并copy原来的数据,效率肯定会很低,因此我们在对字符串改变次数少的时候可以考虑使用String
b>StringBuffer
关键变量:
1 /** 2 * A cache of the last value returned by toString. Cleared 3 * whenever the StringBuffer is modified. 4 */ 5 private transient char[] toStringCache; 6 7 /** 8 * The value is used for character storage. 9 */ 10 char[] value;//StringBuffer是把字符串放到value容器中 11 12 /** 13 * The count is the number of characters used. 14 */ 15 int count;//已使用的空间
StringBuffer是通过ensureCapacityInternal(int minimumCapacity)方法防止数据溢出的,当append字符串str时,先判断count+str.length-value.length>0如果value空间不足时,新建空间newValue并把value赋值到newValue,最后把newValue赋值给value,源码为:
1 public AbstractStringBuilder append(String str) { 2 if (str == null) 3 return appendNull(); 4 int len = str.length(); 5 ensureCapacityInternal(count + len); 6 str.getChars(0, len, value, count);//把字符串放到value空间中 7 count += len; 8 return this; 9 } 10 //确定value空间是否足够,不足则新建空间,并复制数据 11 private void ensureCapacityInternal(int minimumCapacity) { 12 // overflow-conscious code 13 if (minimumCapacity - value.length > 0) { 14 value = Arrays.copyOf(value, 15 newCapacity(minimumCapacity)); 16 } 17 }
其中insert,delete原理大致相同,都是对value空间的操作
需要注意的是:
1>StringBuffer所有public修饰的方法都是通过synchronized关键字保证线程安全的
2>StringBuffer有个toStringCache变量,用来缓存数据的,每当对value操作之前都需要把toStringCache数据清除
变量解释:返回最后一次toString的缓存值,一旦StringBuffer被修改就清除这个缓存值。
c>StringBuilder
StringBuilder的实现原理和StringBuffer的实现原理是相同的,只是StringBuilder是非线程安全的,并且没有使用toStringCache
总结:
执行速度:String<StringBuffer<StringBuilder
安全性:StringBuffer是线程安全的,StringBuilder非线程安全的