java 字符串 扩容 16_thinking in java (三十四) ----- StringBuffer详解与String

StringBuffer是线程安全的可变字符序列,他继承于AbstractStringBuilder,实现了CharSequence接口,StringBuilder也是继承于AbstractStringBuilder的子类,但是线程不安全。

关系图:

StringBuffer源码

1,定义

public final class String

implements java.io.Serializable, Comparable, 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

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来实现不允许多线程同时访问;因此就不单独写了

原文:https://www.cnblogs.com/skywang12345/p/string03.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值