第二十七讲 常用类——StringBuffer与StringBuilder
StringBuffer
概述
我们如果对字符串进行拼接操作的话,每次拼接时,都会构建一个新的String对象,既耗时又浪费空间。而StringBuffer就可以解决这个问题。StringBuffer是一个线程安全的可变字符序列(即字符串缓冲区),它是一个容器。
特点
- 长度可以变化;
- 可以对内容通过指定的方法进行修改;
- 容器对象一般都会具备对容器中的元素进行操作的功能,比如增删改查;
- 缓冲区中可以存储不同类型的数据;
- 最终缓冲区存储完的数据都会变成字符串。
试看以下代码:
String str = "a" + 4 + "c";
如果我们分析以上代码在内存中的变化情况,可得出以下结论:
- 先创建一个字符串缓冲区容器;
- 将要组成字符串的元素先存储起来;
- 最后将缓冲区中填充的数据变成字符串。
用代码来表示就是:
str = new StringBuffer().append("a").append(4).append("c").toString();
常见操作方法
添加功能
package cn.liayun;
public class StringBufferDemo {
public static void main(String[] args) {
method_add();
}
private static void method_add() {
StringBuffer sb = new StringBuffer();
sb.append("abc").append(true).append(34);//方法调用链。
sb.insert(1, "qq");
// System.out.println(sb.toString());//aqqbctrue34
System.out.println(sb);//println()方法会将所有要打印的数据先转成字符串再输出,对于对象会自动调用toString()方法。
}
}
关于输出打印println()和print()方法,我们应注意:它俩会将所有要打印的数据先转成字符串再输出,对于对象会自动调用toString()方法。
删除功能
package cn.liayun;
public class StringBufferDemo {
public static void main(String[] args) {
method_delete();
}
private static void method_delete() {
StringBuffer sb = new StringBuffer("abcde");
//需求:我要删除bc这个字符串,肿么办?
// sb.delete(1, 3);
//需求:清空缓冲区,肿么办?
// sb.delete(0, sb.length());
//需求:我要删除c这个字符,肿么办?
sb.deleteCharAt(2);
System.out.println(sb);
}
}
获取功能
替换功能
package cn.liayun;
public class StringBufferDemo {
public static void main(String[] args) {
method_update();
}
private static void method_update() {
StringBuffer sb = new StringBuffer("abcde");
// 需求:我要把"bcd"这个数据替换为"java"
// sb.replace(1, 4, "java");
// 需求:我要把字符'c'替换为字符'k'
sb.setCharAt(2, 'k');
System.out.println(sb);
}
}
反转功能
package cn.liayun;
public class StringBufferDemo {
public static void main(String[] args) {
method_reverse();
}
private static void method_reverse() {
StringBuffer sb = new StringBuffer();
sb.append("侠美美是我");
System.out.println(sb);
sb.reverse();
System.out.println(sb);
}
}
StringBuffer类的内部原理——可变长度的数组
查看API帮助文档,我们发现StringBuffer类有一个空参构造方法,如下:
API帮助文档对其的解释是:
构造一个其中不带字符的字符串缓冲区,其初始容量为16个字符。
说明字符串缓冲区中维护了一个”可变长度的数组”,所谓”可变长度的数组”其实就是超出内部数组长度后,新建数组长度要是原数组的1.x(1.5或者1.75等)倍数,并将原数组的数据复制到新数组中,并将新的元素也添加到新数组中。
StringBuffer类的练习题
练习一,通过缓冲区,将要打印的矩形组成元素*
进行存储后,一次性返回,并输出。
public class StringBufferTest {
public static void main(String[] args) {
String rec = draw(8, 5);
System.out.println(rec);
}
/*
* 画矩形的功能
* 将需要组成矩形的元素进行临时存储
*/
public static String draw(int row, int col) {
// 定义一个临时容器
StringBuffer sb = new StringBuffer();
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
sb.append("*");
}
sb.append("\n");
}
return sb.toString();
}
}
练习二,将int数组的元素转成字符串,格式为[34, 12, 67]。
public class StringBufferTest {
public static void main(String[] args) {
int[] arr = {34, 12, 67, 43, 69};
String s = toString(arr);
System.out.println(s);
}
/*
* int数组转成字符串,通过StringBuffer
*/
public static String toString(int[] arr) {
StringBuffer sb = new StringBuffer();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if (i != arr.length - 1)
sb.append(arr[i] + ",");
else
sb.append(arr[i] + "]");
}
return sb.toString();
}
}
练习三,以下程序代码,会打印输出什么?
public class StringBufferTest {
public static void main(String[] args) {
StringBuffer buf1 = new StringBuffer("hello");
StringBuffer buf2 = new StringBuffer("java");
test(buf1, buf2);
System.out.println(buf1 + "..." + buf2);
}
public static void test(StringBuffer buf1, StringBuffer buf2) {
buf1.append(buf2);
buf1 = buf2;
}
}
好久都没分析对象内存结构图了,瞬间就懵逼了,画了如下的一张图之后,才醒悟过来,惭愧!!!
所以,以上程序运行会在控制台中输出:
hellojava…java
StringBuilder
JDK1.5版本之后,出现了StringBuilder,它和StringBuffer用法一样,所以就不再过多讲解了。不过,StringBuffer与StringBuilder的区别是StringBuffer是线程同步的,而StringBuilder是线程不同步的。
在实际开发中,一般可以建议选择StringBuilder,因为其速度快。但是将StringBuilder的实例用于多个线程时是不安全的。如果需要这样的同步,则建议使用StringBuffer。