一、String,StringBuilder,StringBuffer的大概了解
大家知道String,StringBuilder,StringBuffer三个的基本应用场景。
- String会一直创建新对象,因此频繁创建对象的场景不适合用。
- StringBuilder则可以避免这个情况,因此频繁对字符串操作的场景使用StringBuilder比较合适。
- 但是StringBuilder并不是线程安全的,如果要线程安全,需要使用StringBuffer。
二、为什么String会一直创建新对象?
1 private final char value[];
- String代码中,字符是存在一个 final 的 char value[]里面的。
- 由于final指定了存储的内从是固定的,因此如果有append之类的操作的话要重新开辟新的内存。
- 要注意的是即使 value[]是final的,它也是可以改变里面的内容的。
下面这写法是正确的。不会报错。
1 final char[] ss = {'a', 'b', 'c'}; 2 ss[0] = 'b'; 3 ss[1] = 'c';
但是String类并没有提供这么一个接口能直接修改value数组。其中的replace是返回了一个新的String 对象。并不是在原先的数组上进行修改。
1 public String replace(char oldChar, char newChar) { 2 if (oldChar != newChar) { 3 int len = value.length; 4 int i = -1; 5 char[] val = value; /* avoid getfield opcode */ 6 7 while (++i < len) { 8 if (val[i] == oldChar) { 9 break; 10 } 11 } 12 if (i < len) { 13 char buf[] = new char[len]; 14 for (int j = 0; j < i; j++) { 15 buf[j] = val[j]; 16 } 17 while (i < len) { 18 char c = val[i]; 19 buf[i] = (c == oldChar) ? newChar : c; 20 i++; 21 } 22 return new String(buf, true); 23 } 24 } 25 return this; 26 }
三、StringBuilder中的主要内容
这个类继承了AbstractStringBuilder。AbstractStringBuilder里面封装了大部分内容。初始化大小为16个字符。
1、相比较String中的value,这个不是final 类型的。
char[] value;
2、newCapacity方法。
- 将原始的capacity*2+2
- 判断新的容量是不是合法
- 最大容量不会超过MAX_ARRAY_SIZE。MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8.
1 private int newCapacity(int minCapacity) { 2 // overflow-conscious code 3 int newCapacity = (value.length << 1) + 2; 4 if (newCapacity - minCapacity < 0) { 5 newCapacity = minCapacity; 6 } 7 return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) 8 ? hugeCapacity(minCapacity) 9 : newCapacity; 10 }
3、append方法
其实最终调用了System.arrayCopy将append中的String value copy到了StringBuilder 中的 value。
1 public AbstractStringBuilder append(StringBuffer sb) { 2 if (sb == null) 3 return appendNull(); 4 int len = sb.length(); 5 ensureCapacityInternal(count + len); 6 sb.getChars(0, len, value, count); 7 count += len; 8 return this; 9 }
最终调用getChars方法。
1 public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { 2 if (srcBegin < 0) { 3 throw new StringIndexOutOfBoundsException(srcBegin); 4 } 5 if (srcEnd > value.length) { 6 throw new StringIndexOutOfBoundsException(srcEnd); 7 } 8 if (srcBegin > srcEnd) { 9 throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); 10 } 11 System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); 12 }
四、StringBuffer中的主要内容
这个类同样继承了AbstractStringBuilder。
1 public final class StringBuffer 2 extends AbstractStringBuilder 3 implements java.io.Serializable, CharSequence
但是几乎所有的方法都加了同步。因此是线程安全的。
1、append
1 @Override 2 public synchronized StringBuffer append(String str) { 3 toStringCache = null; 4 super.append(str); 5 return this; 6 }
2、chartAt
1 @Override 2 public synchronized char charAt(int index) { 3 if ((index < 0) || (index >= count)) 4 throw new StringIndexOutOfBoundsException(index); 5 return value[index]; 6 }
其中StringBuffer里面有个 char [] toStringCache。当调用toString的时候,这个就会缓存StringBuffer的内容。当对StringBuffer有修改的时候,这个数组就会设定为null。
1 private transient char[] toStringCache;