1、概述
java.lang.StringBuffer代表可变的字符序列 ,可以对字符 串内容进行增删改,此时不会产生新的对象。
StringBuilder代表也是可变的字符序列,可以对字符串内容进行增删改,此时不会产生新的对象。
StringBuffer的源码截图:
StringBuilder的源码截图:
相比String类的 private final byte[] value; 就是Stringbuffer和StringBuilder都是可变的字符序列,它们都继承了AbstractStringBuffer,而这个抽象类一个byte[ ] value(不是final的)来存储字符串用的。
首先来一道面试常问的题:
2、String、StringBuffer、StringBuilder的异同?
String:不可变的字符序列:底层使用char[ ]存储
StringBuffer:可变的字符序列:线程是安全的,效率低,底层是使用char[ ]存储的
StringBuilder:可变的字符序列:线程也是不安全的,效率高,底层使用char [ ] 存储的
3、源码解析
三者的源码分析:
String str1 = new String(); 相当于char [ ] value = new char[0]
String str2 = new String("abc"); 相当于char [ ] value = new char[ ]{'a','b','c'}
StringBuffer sber1 = new StringBuffer(); 底层是默认帮你创建一个长度16的字符数组,char [ ] value = new char[16]
父类的有参构造方法:
StringBuffer sber2 = new StringBuffer("abc"); 底层是默认帮你创建一个所创建的字符串长度 + 16 ,char [ ] value = new char [ "abc".length +16]
父类的有参构造方法:
1、这里就会有疑问了???,要是创建了个"abc"的StringBuffer的字符串,我们在输出其长度,length()会是19还是3??
StringBuffer stringBuffer = new StringBuffer("abc");
System.out.println(stringBuffer.length());
答案是3,其中查看源码在使用debug模式可以看出是,它把str="abc“,在使用str.length;修改了父类的AbstractStringbuilder的count的值,修改成3.
在查看count的解释时,以及length()方法:被使用的used
获取长度是被使用的
2、还有一个疑问就是,添加时数组的底层不足以容下???不会数组越界???
其实就是底层扩容数组
当超过默认大小后,会创建一个更大的数组【创建(扩容原来的容量)*2 + 2】无参构造创建时,原本的容量是16,超过后扩容是34,并将原先的数组内容复制过来,再丢弃旧的数组。
源码通过debug过程:
StringBuilder和StringBuffer是一样的,方法内容。只是方法上加了synchronized同步,解决线程安全问题。
4、StringBuffer的常用方法
方法原型 | 作用及含义 |
StringBuffer append(xxx) | 提供了很多的append()方法,用于进行字符串拼接 |
StringBuffer delete(int start,int end) | 删除指定下标的位置的内容 |
StringBuffer replace(int start, int end, String str) | 把[start,end)下标的位置替换为str |
StringBuffer insert(int offset, xxx) | 在指定下标的位置插入xxx |
StringBuffer reverse() | 把当前字符序列逆转 |
public int indexOf(String str) | 返回指定子字符串在此字符串中第一次出现处的索引 |
public int length() | 返回字符串的长度 |
public char charAt(int n ) | 返回该索引下的字符 |
public void setCharAt(int n ,char ch) | 把ch字符设置到字符串中指定下标位置 |
当append和insert时,如果原来value数组长度不够,可扩容
简单总结起来就是 增【append()】 删 【delete()】 改 【 setcharAt(int n)】 查 【 charAt(int n)】 插入 【 insert(int index,xxx)】
5、String、StringBuffer、StringBuilder的效率对比
代码演示:
package day02;
import org.junit.Test;
public class StringMain {
@Test
public void test01(){
long startTime = 0L;
long endTime = 0L;
String text = "";
StringBuffer buffer = new StringBuffer("");
StringBuilder builder = new StringBuilder("");
//开始对比
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
text = text + i;
}
endTime = System.currentTimeMillis();
System.out.println("String的执行时间:" + (endTime - startTime));
}
}
输出:
StringBuffer的执行时间:10
StringBuilder的执行时间:4
String的执行时间:223
清楚的看见就是String是最慢的,而StringBuffer是第二(它保证了线程的安全,所以比StringBuilder慢)StringBuilder是最快的。
效率高到低:StringBuilder > StringBuffer > String
面试题:
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str);
System.out.println(sb.length());//
System.out.println(sb);//
StringBuffer sb1 = new StringBuffer(str);
System.out.println(sb1);
输出是?
4
null
报错
查看源码才知道: