StringBuffer是线程安全的可变字符序列,他继承于AbstractStringBuilder,实现了CharSequence接口,StringBuilder也是继承于AbstractStringBuilder的子类,但是线程不安全。
关系图:
StringBuffer源码
1,定义
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {…}
2,属性:
static final long serialVersionUID = 3388685877147921107L;
3,构造函数
1)构造一个不带字符的字符串缓冲区,初始容量为16个字符
public StringBuffer() {
super(16);
}
继承的是父类的构造函数
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
2)构造一个不带字符,但是又指定容量的字符串缓冲区
public StringBuffer(int capacity) {
super(capacity);
}
3)构造一个字符串缓冲区,将其内容初始化为指定的字符串内容,该字符串的初始容量是16加字符串长度
public StringBuffer(String str) {
//这个执行父类的带参构造函数AbstractStringBuilder(int capacity)
super(str.length() + 16);
append(str);
}
append 是用 synchronized 修饰的,所以是线程安全的
public synchronized StringBuffer append(String str) {
//执行父类的append(str)
super.append(str);
return this;
}
父类的append方法
public synchronized StringBuffer append(String str) {
//执行父类的append(str)
super.append(str);
return this;
}
扩大容量的方法
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code:判断是否需要扩容,也就是说原来的capacity是否足够大
if (minimumCapacity - value.length > 0) //20-19=1,1>0
expandCapacity(minimumCapacity);
}
void expandCapacity(int minimumCapacity) {
//新容量 原始容量 * 2 + 2
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0) //扩容后的容量-字符串实际长度<0(就是说如果扩容后还装不下),
newCapacity = minimumCapacity; //则使用字符串实际长度作为StringBuffer的capacity
if (newCapacity < 0) {//扩容后的容量超过integer的最大值
if (minimumCapacity < 0) // overflow //最终容量超过integer的最大值
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
//将旧的值剪切到新的字符数组。
value = Arrays.copyOf(value, newCapacity);
}
4,常用方法
4.1append源码
1)append StringBuffer
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return append("null");
int len = sb.length();
int newCount = count + len;
if (newCount > value.length)
expandCapacity(newCount); // 若value存储容量不够需扩容。扩容方法省略暂不分析,基本上根据Arrays.copyOf()方法,复制指定的数组,以使副本具有指定的长度。到头来copyOf的源码一样是利用arraycopy方法来复制数组和扩容
sb.getChars(0, len, value, count); //把sb的内容0->len复制到value中,注意value参数,此时的value是已经扩容后的value。
count = newCount; // 更新新count值
return this;
}
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) // dstBegin就是原有count接下来的位置
{
if (srcBegin < 0)
throw new StringIndexOutOfBoundsException(srcBegin);
if ((srcEnd < 0) || (srcEnd > count))
throw new StringIndexOutOfBoundsException(srcEnd);
if (srcBegin > srcEnd)
throw new StringIndexOutOfBoundsException("srcBegin > srcEnd"); //以上是Bound Check
System.arraycopy(value, srcBegin,dst, dstBegin, srcEnd - srcBegin); // 从指定源数组中复制一个数组
} //AbstractStringBuilder里定义的getChars方法体,是对System.arraycopy方法 + 边界检查的进一步封装而已。
2)append char[] str
public AbstractStringBuilder append(char[] str) {
int len = str.length; //数组长度
ensureCapacityInternal(count + len); //扩容
System.arraycopy(str, 0, value, count, len);
count += len;
return this;
}
3)添加字符数组str从偏移量offset开始,长度为len的子数组
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0) // let arraycopy report AIOOBE for len < 0
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
}
4)boolean b
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
value[count++] = 't';
value[count++] = 'r';
value[count++] = 'u';
value[count++] = 'e';
} else {
ensureCapacityInternal(count + 5);
value[count++] = 'f';
value[count++] = 'a';
value[count++] = 'l';
value[count++] = 's';
value[count++] = 'e';
}
return this;
}
5)char c
public AbstractStringBuilder append(char c) {
//字符的长度为 1 ,只需增加一个
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
6)int i
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
// stringSizeOfInt,判断输入的整数i占多少位,如负数+1,方法源码往后看。
int appendedLength = (i < 0) ? stringSizeOfInt(-i) + 1
: stringSizeOfInt(i);
int spaceNeeded = count + appendedLength;
if (spaceNeeded > value.length) // 检查容量,是否需扩容
expandCapacity(spaceNeeded);
Integer.getChars(i, spaceNeeded, value); // 把整型i以字符的形式加进buffer(value)中
count = spaceNeeded; //更新count长度。
return this;
}
7)long i
public AbstractStringBuilder append(long l) {
if (l == Long.MIN_VALUE) {
append("-9223372036854775808");
return this;
}
int appendedLength = (l < 0) ? Long.stringSize(-l) + 1
: Long.stringSize(l);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Long.getChars(l, spaceNeeded, value);
count = spaceNeeded;
return this; }
// Requires positive x
static int stringSizeOfLong(long x) {
long p = 10;
for (int i=1; i<19; i++) {
if (x < p) // 与两位数10比较,小于返回占一位
return i;
p = 10*p; //如此类推,小于100占2位
}
return 19; // 最大19位
}
4.2 delete
delete(int start, int end) 删除字符序列中从start开始,end结束的子序列
public AbstractStringBuilder delete(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
end = count;
if (start > end)
throw new StringIndexOutOfBoundsException();
int len = end - start;
if (len > 0) {
System.arraycopy(value, start+len, value, start, count-end);
count -= len;
}
return this;
}
deleteCharAt(int index)
public AbstractStringBuilder deleteCharAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
System.arraycopy(value, index+1, value, index, count-index-1);
count--;
return this;
}
4.3replace
public AbstractStringBuilder replace(int start, int end, String str) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (start > count)
throw new StringIndexOutOfBoundsException("start > length()");
if (start > end)
throw new StringIndexOutOfBoundsException("start > end");
// 以上都是一些Bounds Checking,没什么好说。
if (end > count) //若替换字符边界超出字符长度,把字符长度赋予边界量
end = count;
int len = str.length();
//新字符长度,要加上替换长度,减去截取长度
int newCount = count + len - (end - start);
if (newCount > value.length) //是否大于已有容量,是则扩容
expandCapacity(newCount);
//复制数组,先预留替换字符串str的长度,看后面的解释。
System.arraycopy(value, end, value, start + len, count - end);
str.getChars(value, start);//填充str到value,start索引开始
count = newCount;
return this;
}
4.4 insert 方法(其实跟replace差不多,都是先通过System.arraycopy Method在字符数组value中预留一个空间,再用多一次这方法插入str或char[]。)
(1)insert(int index, char str[], int offset,int len)
// StringBuffer里面,调用父类的方法
public synchronized StringBuffer insert(int index, char str[], int offset,
int len)
{
super.insert(index, str, offset, len);
return this;
}
public AbstractStringBuilder insert(int index, char str[], int offset,
int len)
{
// bounds checking
if ((index < 0) || (index > length()))
throw new StringIndexOutOfBoundsException(index);
// 注意:offset的值,offset + len不应大于str.length
if ((offset < 0) || (len < 0) || (offset > str.length - len))
throw new StringIndexOutOfBoundsException(
"offset " + offset + ", len " + len + ", str.length "
+ str.length);
int newCount = count + len;
if (newCount > value.length)
expandCapacity(newCount);
// 从index开始,预留了长度为len的空间;从index+len开始,将长度为count-index的后半截补充。
System.arraycopy(value, index, value, index + len, count - index);
// str字符串数组,从索引offset开始复制,长度为len,复制到以索引index位置的value字符串数组。
System.arraycopy(str, offset, value, index, len);
count = newCount; //记得更新实际字符长度(字符数量)。
return this;
}
StringBuffer实例
package test;
/**
* StringBuffer 演示程序
*
* @author skywang
*/
import java.util.HashMap;
public class StringBufferTest {
public static void main(String[] args) {
testInsertAPIs() ;
// testAppendAPIs() ;
// testReplaceAPIs() ;
// testDeleteAPIs() ;
// testIndexAPIs() ;
// testOtherAPIs() ;
}
/**
* StringBuffer 的其它API示例
*/
private static void testOtherAPIs() {
System.out.println("-------------------------------- testOtherAPIs --------------------------------");
StringBuffer sbuilder = new StringBuffer("012");
int cap = sbuilder.capacity();
System.out.printf("cap=%d\n", cap);
char c = sbuilder.charAt(1);
System.out.printf("c=%c\n", c);
char[] carr = new char[4];
sbuilder.getChars(0, 2, carr, 0);
for (int i=0; i<carr.length; i++)
System.out.printf("carr[%d]=%c ", i, carr[i]);
System.out.println();
System.out.println();
}
/**
* StringBuffer 中index相关API演示
*/
private static void testIndexAPIs() {
System.out.println("-------------------------------- testIndexAPIs --------------------------------");
StringBuffer sbuilder = new StringBuffer("abcAbcABCabCaBcAbCaBCabc");
System.out.printf("sbuilder=%s\n", sbuilder);
// 1. 从前往后,找出"bc"第一次出现的位置
System.out.printf("%-30s = %d\n", "sbuilder.indexOf(\"bc\")", sbuilder.indexOf("bc"));
// 2. 从位置5开始,从前往后,找出"bc"第一次出现的位置
System.out.printf("%-30s = %d\n", "sbuilder.indexOf(\"bc\", 5)", sbuilder.indexOf("bc", 5));
// 3. 从后往前,找出"bc"第一次出现的位置
System.out.printf("%-30s = %d\n", "sbuilder.lastIndexOf(\"bc\")", sbuilder.lastIndexOf("bc"));
// 4. 从位置4开始,从后往前,找出"bc"第一次出现的位置
System.out.printf("%-30s = %d\n", "sbuilder.lastIndexOf(\"bc\", 4)", sbuilder.lastIndexOf("bc", 4));
System.out.println();
}
/**
* StringBuffer 的replace()示例
*/
private static void testReplaceAPIs() {
System.out.println("-------------------------------- testReplaceAPIs ------------------------------");
StringBuffer sbuilder;
sbuilder = new StringBuffer("0123456789");
sbuilder.replace(0, 3, "ABCDE");
System.out.printf("sbuilder=%s\n", sbuilder);
sbuilder = new StringBuffer("0123456789");
sbuilder.reverse();
System.out.printf("sbuilder=%s\n", sbuilder);
sbuilder = new StringBuffer("0123456789");
sbuilder.setCharAt(0, 'M');
System.out.printf("sbuilder=%s\n", sbuilder);
System.out.println();
}
/**
* StringBuffer 的delete()示例
*/
private static void testDeleteAPIs() {
System.out.println("-------------------------------- testDeleteAPIs -------------------------------");
StringBuffer sbuilder = new StringBuffer("0123456789");
// 删除位置0的字符,剩余字符是“123456789”。
sbuilder.deleteCharAt(0);
// 删除位置3(包括)到位置6(不包括)之间的字符,剩余字符是“123789”。
sbuilder.delete(3,6);
// 获取sb中从位置1开始的字符串
String str1 = sbuilder.substring(1);
// 获取sb中从位置3(包括)到位置5(不包括)之间的字符串
String str2 = sbuilder.substring(3, 5);
// 获取sb中从位置3(包括)到位置5(不包括)之间的字符串,获取的对象是CharSequence对象,此处转型为String
String str3 = (String)sbuilder.subSequence(3, 5);
System.out.printf("sbuilder=%s\nstr1=%s\nstr2=%s\nstr3=%s\n",
sbuilder, str1, str2, str3);
System.out.println();
}
/**
* StringBuffer 的insert()示例
*/
private static void testInsertAPIs() {
System.out.println("-------------------------------- testInsertAPIs -------------------------------");
StringBuffer sbuilder = new StringBuffer();
// 在位置0处插入字符数组
sbuilder.insert(0, new char[]{'a','b','c','d','e'});
// 在位置0处插入字符数组。0表示字符数组起始位置,3表示长度
sbuilder.insert(0, new char[]{'A','B','C','D','E'}, 0, 3);
// 在位置0处插入float
sbuilder.insert(0, 1.414f);
// 在位置0处插入double
sbuilder.insert(0, 3.14159d);
// 在位置0处插入boolean
sbuilder.insert(0, true);
// 在位置0处插入char
sbuilder.insert(0, '\n');
// 在位置0处插入int
sbuilder.insert(0, 100);
// 在位置0处插入long
sbuilder.insert(0, 12345L);
// 在位置0处插入StringBuilder对象
sbuilder.insert(0, new StringBuffer("StringBuilder"));
// 在位置0处插入StringBuilder对象。6表示被在位置0处插入对象的起始位置(包括),13是结束位置(不包括)
sbuilder.insert(0, new StringBuffer("STRINGBUILDER"), 6, 13);
// 在位置0处插入StringBuffer对象。
sbuilder.insert(0, new StringBuffer("StringBuffer"));
// 在位置0处插入StringBuffer对象。6表示被在位置0处插入对象的起始位置(包括),12是结束位置(不包括)
sbuilder.insert(0, new StringBuffer("STRINGBUFFER"), 6, 12);
// 在位置0处插入String对象。
sbuilder.insert(0, "String");
// 在位置0处插入String对象。1表示被在位置0处插入对象的起始位置(包括),6是结束位置(不包括)
sbuilder.insert(0, "0123456789", 1, 6);
sbuilder.insert(0, '\n');
// 在位置0处插入Object对象。此处以HashMap为例
HashMap map = new HashMap();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
sbuilder.insert(0, map);
System.out.printf("%s\n\n", sbuilder);
}
/**
* StringBuffer 的append()示例
*/
private static void testAppendAPIs() {
System.out.println("-------------------------------- testAppendAPIs -------------------------------");
StringBuffer sbuilder = new StringBuffer();
// 追加字符数组
sbuilder.append(new char[]{'a','b','c','d','e'});
// 追加字符数组。0表示字符数组起始位置,3表示长度
sbuilder.append(new char[]{'A','B','C','D','E'}, 0, 3);
// 追加float
sbuilder.append(1.414f);
// 追加double
sbuilder.append(3.14159d);
// 追加boolean
sbuilder.append(true);
// 追加char
sbuilder.append('\n');
// 追加int
sbuilder.append(100);
// 追加long
sbuilder.append(12345L);
// 追加StringBuilder对象
sbuilder.append(new StringBuffer("StringBuilder"));
// 追加StringBuilder对象。6表示被追加对象的起始位置(包括),13是结束位置(不包括)
sbuilder.append(new StringBuffer("STRINGBUILDER"), 6, 13);
// 追加StringBuffer对象。
sbuilder.append(new StringBuffer("StringBuffer"));
// 追加StringBuffer对象。6表示被追加对象的起始位置(包括),12是结束位置(不包括)
sbuilder.append(new StringBuffer("STRINGBUFFER"), 6, 12);
// 追加String对象。
sbuilder.append("String");
// 追加String对象。1表示被追加对象的起始位置(包括),6是结束位置(不包括)
sbuilder.append("0123456789", 1, 6);
sbuilder.append('\n');
// 追加Object对象。此处以HashMap为例
HashMap map = new HashMap();
map.put("1", "one");
map.put("2", "two");
map.put("3", "three");
sbuilder.append(map);
sbuilder.append('\n');
// 追加unicode编码
sbuilder.appendCodePoint(0x5b57); // 0x5b57是“字”的unicode编码
sbuilder.appendCodePoint(0x7b26); // 0x7b26是“符”的unicode编码
sbuilder.appendCodePoint(0x7f16); // 0x7f16是“编”的unicode编码
sbuilder.appendCodePoint(0x7801); // 0x7801是“码”的unicode编码
System.out.printf("%s\n\n", sbuilder);
}
}
结果:
-------------------------------- testInsertAPIs -------------------------------
{3=three, 2=two, 1=one}
12345StringBUFFERStringBufferBUILDERStringBuilder12345100
true3.141591.414ABCabcde
-------------------------------- testAppendAPIs -------------------------------
abcdeABC1.4143.14159true
10012345StringBuilderBUILDERStringBufferBUFFERString12345
{3=three, 2=two, 1=one}
字符编码
-------------------------------- testReplaceAPIs ------------------------------
sbuilder=ABCDE3456789
sbuilder=9876543210
sbuilder=M123456789
-------------------------------- testDeleteAPIs -------------------------------
sbuilder=123789
str1=23789
str2=78
str3=78
-------------------------------- testIndexAPIs --------------------------------
sbuilder=abcAbcABCabCaBcAbCaBCabc
sbuilder.indexOf("bc") = 1
sbuilder.indexOf("bc", 5) = 22
sbuilder.lastIndexOf("bc") = 22
sbuilder.lastIndexOf("bc", 4) = 4
-------------------------------- testOtherAPIs --------------------------------
cap=26
c=6
carr[0]=3 carr[1]=4 carr[2]=5 carr[3]=6
StringBuilder
两者所有API高度一致,StringBuilder、StringBuffer一个线程安全、一个线程不安全,其实原因也就来自于StringBuffer中append方法使用了synchronized来实现不允许多线程同时访问;因此就不单独写了