java-Stringbuffer
文章首发于我的博客Lunatic,转载请注明出处
StringBuffer类的理解
继承关系图示
-
java. lang String Buffer代表可变的字符序列,可以对字符串内容进行增删。
-
很多方法与 String相同,但 String Buffer是可变长度的。
-
StringBuffer是一个容器。
-
StringBuffer是一个final类,不可以被继承
-
StringBuffer
继承了AbstractStringBuffer
类,而AbstractStringBuffer
类里面维护了一个数组char[] value; //区别于String里面的数组,此数组没有final关键字,说明此数组是可以被更改的,也说明了此数组是在堆空间中的;不用每次都更换地址(即不是每次创建新对象),所以效率高于 String
StringBuffer底层源码分析
-
StringBuffer类有四个构造方法:
// 构造器一 public StringBuffer() { } // 构造器二 public StringBuffer(int capacity) { } // 构造器三 public StringBuffer(String str) { } // 构造器四 public StringBuffer(CharSequence seq) { }
-
使用构造器一创建对象
public StringBuffer() { super(16); } // 调用父类的有参构造器,参数:16 AbstractStringBuilder(int capacity) { value = new char[capacity]; // 此处参数传16,value指向一个char[],数组的初始大小为16 }
-
使用构造器二创建对象
public StringBuffer(int capacity) { super(capacity); // 调用父类的有参构造器,参数:(构造方法中传进来的参数) } AbstractStringBuilder(int capacity) { value = new char[capacity]; //此处参数传16,value指向一个char[],数组的初始大小为自己指定的大小 } // 此构造方法会开辟指定大小的数组长度
-
使用构造器三创建对象
public StringBuffer(String str) { super(str.length() + 16); //调用父类的有参构造器,参数:该字符串的长度+16 append(str); // 构建好char[]之后,调用append() } // 父类构造方法的调用2,3说过,此处不再说明
-
使用构造器四创建对象和构造器三差不多。
-
关于StringBuffer的底层扩容机制
// 使用append() public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); // 调用父类的append() return this; } public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); // 此方法用来保证容量 str.getChars(0, len, value, count); count += len; // count:用来记录字符的数量 return this; } private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { //如果需要的最小容量比数组的容量大,则开辟新数组 value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } private int newCapacity(int minCapacity) { // overflow-conscious code int newCapacity = (value.length << 1) + 2; //新开辟数组的容量是原数组容量的二倍加二 if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; // 如果扩容之后还不够就直接扩容至所需要的容量 } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; }
StringBuffer和String的区别
-
String保存的是字符串常量,里面的值(地址值)不能更改,每次String类的更新实际上就是更改地址,效率较低
private final char value;
-
String Buffer保存的是字符串变量,里面的值可以更改,每次String Buffer的更新实际上可以更新内容,不用每次更新地址,效率较高
char[] value; ∥这个放在堆.
StringBuffer和String的相互转换
-
String -> StringBuffer
String str = "hello tom"; //方式1 使用构造器 //注意: 返回的才是StringBuffer对象,对str 本身没有影响 StringBuffer stringBuffer = new StringBuffer(str); //方式2 使用的是append方法 StringBuffer stringBuffer1 = new StringBuffer(); stringBuffer1 = stringBuffer1.append(str);
-
StringBuffer -> String
StringBuffer stringBuffer3 = new StringBuffer("韩顺平教育"); //方式1 使用StringBuffer提供的 toString方法 String s = stringBuffer3.toString(); //方式2: 使用构造器来搞定 String s1 = new String(stringBuffer3);
StringBuffer类的常用方法
-
append():添加元素
说明:可以连续使用append()添加元素,使用println()输出的时候,输出的是字符串,因为它底层调用了toString(),返回了一个字符串对象public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }
-
delete()::删除元素
-
replace():替换元素
-
insert():插入元素
-
length():获取StringBuffer中所含元素的个数
StringBuffer测试题
- 第一个
String str=null;
StringBuffer sb= new StringBuffer();
sb. append(str);
System. out. println(sb.length()); //4
System.out.println(sb); // null
底层源码分析
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str); //调用父类的append();
return this;
}
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull(); // 如果添加的字符串树null,则调用appendNull()
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this; // 将null每个字符添加进去
}
总结:StringBuffer使用append()添加null的时候,不会出现空指针异常的问题
- 第二个
StringBuffer sbl= new StringBuffer(str); // 会报空指针异常的错误
System. out. printIn(sbl)
底层源码分析
public StringBuffer(String str) {
super(str.length() + 16); // 在调用父类构造器的时候会出现null.length(),这时候会出现空指针异常的问题
append(str);
}
总结:StringBuffer使用构造方法添加null的时候会出现空指针异常的问题