文章目录
一、String、StringBuffer和StringBuilder的区别
- 相同点:
- 都是与字符串相关的类
- 底层结构都是使用 char[] 存储字符串
- 不同点:
- String是不可变的字符序列
- StringBuffer是可变的字符序列,线程安全,但效率偏低
- StringBuilder是可变的字符序列,线程不安全,但效率高
StringBuilder和StringBuffer的不同仅仅是,StringBuilder的所有方法都是线程安全的,这篇文章仅仅使用StringBuffer作为参考分析,两者方法的调用都是一样的
二、StringBuffer源码分析
1. 成员变量
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
// StringBuffer类的成员变量字符数组没有使用final修饰,因此它是可变的
private transient char[] toStringCache;
static final long serialVersionUID = 3388685877147921107L;
// 其他构造器
2. 构造器
(1)源码中字符数组的大小如何初始化?
1. StringBuffer对象在构建过程中,默认的字符数组value的大小为16:
// StringBuffer源码的构造器
public StringBuffer() {
super(16);
}
// ——————————————————————————————————————————————————————————
// StringBuffer的父类AbstractStringBuilder对应的构造器:
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
2. 对StringBuffer的构造器传入一个字符串,value的大小为字符串长度+16:
public StringBuffer(String str) {
super(str.length() + 16);
append(str); // 创建好value后将字符串添加给value
}
// ——————————————————————————————————————————————————————————
// 对应父类中的构造器
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
3. 如果想要字符串可以改变,又不想频繁扩容,可以给构造器传入一个整数用来创建想要容量的value:
public StringBuffer(int capacity) {
super(capacity);
}
// ——————————————————————————————————————————————————————————
// 在父类中,传入的整数作为value的长度
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
(2)字符串的长度
- StringBuffer中length()方法返回的不是字符数组value的长度,返回的是count,该变量用于动态的计算字符串的长度
StringBuffer strbuff = new StringBuffer("breaking bad");
System.out.println( strbuff.length()); // strbuff.length() 等于多少?
// ——————————————————————————————————————————————————————————
// StringBuffer源码的length():
public synchronized int length() {
return count; // count是在父类中定义的成员变量
}
// ——————————————————————————————————————————————————————————
// 父类AbstractStringBuilder 中的count:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
// The value is used for character storage.
char[] value;
// The count is the number of characters used.
// 使用count统计字符串长度
int count
// 其他部分源码
(3)如果字符数组的容量填满了,该如何扩容?
- 如果value的剩余空间不足以添加一个新的字符串,通常情况下,源码中扩容的策略有两种:
- 将原字符串长度+新添加的字符串长度得到的值记作minCapacity
- 将value数组的长度*2+2得到新的数组长度为newCapacity ,如果newCapacity 的长度大于minCapacity,则newCapacity 为扩容后的字符数组value的长度
- 如果由1得到的newCapacity 依旧小于minCapacity,则此时直接将minCapacity作为新的字符数组value的长度。
// 由于源码中牵扯的方法比较多,这里放最核心的代码
StringBuffer strbuff = new StringBuffer("breaking bad:");
strbuff.append("Heisenberg");
// ——————————————————————————————————————————————————————————
// 其中minCapacity原字符串长度+要添加的字符串长度
// newCapacity为要扩容的数组长度
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;
}
三. 常用方法
append() 添加
deleteCharAt() 删除指定索引处的字符
delete() 删除一段字符
方法测试:
StringBuffer strbuff = new StringBuffer("breaking bad:");
strbuff.append("\"Heisenberg\"");
strbuff.append(2021);
strbuff.append('Q');
strbuff.append("JavaEE");
System.out.println(strbuff); // 输出:
strbuff.deleteCharAt(strbuff.indexOf("2021"));
System.out.println(strbuff); // 输出:
strbuff.delete(25,strbuff.length());
System.out.println(strbuff); // 输出:
// 运行结果:
breaking bad:"Heisenberg"2021QJavaEE
breaking bad:"Heisenberg"021QJavaEE
breaking bad:"Heisenberg"
replace() 将指定左闭右开区间内的字符成另一串字符
setCharAt() 更改指定索引处的字符
方法测试:
StringBuffer strbuff = new StringBuffer("breaking bad:\"Heisenberg\"");
strbuff.setCharAt(0,'B');
System.out.println(strbuff);
strbuff.replace(14,24,"Walter Hartwell White");
System.out.println(strbuff);
// 运行结果:
Breaking bad:"Heisenberg"
Breaking bad:"Walter Hartwell White"
charAt() 查找指定索引处的字符并返回
indexOf(String str) 查找字符串中首次出现指定子字符串的索引
indexOf(String str,int index) 查找字符串index位置后,子串str首次出现的索引
insert() 在指定索引处进行插入一串字符
StringBuffer strbuff = new StringBuffer("Breaking bad:\"Heisenberg\"");
for (int i = 0; i < strbuff.length(); i++) {
System.out.print(strbuff.charAt(i));
System.out.print(' ');
}
System.out.println();
System.out.println("strbuff.indexOf(\"Heisen\") = " + strbuff.indexOf("Heisen"));
strbuff.insert(strbuff.length()-1,"_");
System.out.println("strbuff = " + strbuff);
// 运行结果:
B r e a k i n g b a d : " H e i s e n b e r g "
strbuff.indexOf("Heisen") = 14
strbuff = Breaking bad:"Heisenberg_"
reverse() 对字符串进行反转
StringBuffer strbuff = new StringBuffer("Breaking bad:\"Heisenberg\"");
System.out.println(strbuff.reverse());
// 运行结果
"grebnesieH":dab gnikaerB
substring() 截取一段子字符串
StringBuffer strbuff = new StringBuffer("Breaking bad:\"Heisenberg\"");
String str = strbuff.substring(14,24);
System.out.println("str = " + str);
System.out.println("strbuff = " + strbuff);
// 运行结果
str = Heisenberg
strbuff = Breaking bad:"Heisenberg"
四、StringBuffer/StringBuilder 与String的转换
- StringBuffer/StringBuilder转化成String:
String.valueOf(str);
- String转化成StringBuffer/StringBuilder:
new StringBuffer(str)/new StringBuilder(str)