Java中StringBuffer类和StringBuilder类的用法及区别:
1、先思考一个问题:
如果我们在开发中,需要进行字符串的频繁拼接,会有什么问题?
因为java中的字符串是不可改变的,每一次拼接都会产生中间产物字符串。这样会占用大量的方法区内存,造成内存空间的浪费。
2、引入StringBuffer对象的使用
使用StringBuffer,字符串缓冲区对象,也是一个用来存字符串的对象,可以大量减少拼接浪费问题,因为StringBuffer中存储字符串的byte[] value是不带final修饰符的。这样的话,你就可以在原来的字符串基础上直接拼接字符串。
StringBuffer使用无参数构造方法时默认创建长度为16的byte[] value来存储字符串。
当你追加字符串时,长度不够时,StringBuffer对象底层会自动实现byte[]数组的扩容。
3、减少底层自动扩容的次数
我们知道数组的扩容效率是很低的,所以如何优化StringBuffer来存储字符串?
就是初始化的时候使用有参数构造函数,传长度过去,你得先预估一下需要长度多少合适,尽量减少StringBuffer在追加字符串时自动扩容的次数。
预估准确,减少扩容次数,提高程序效率。
测试代码:
public class Test01 {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello" + "world";
//思考,上面这两行代码产生了几个对象?
//3个,分别是"hello", "world", "helloworld", 其中"world"是中间产物,让s2指向"helloworld"的中间产物
//这个中间产物"world"保存在方法区字符串常量池当中,它的值是不可变的,造成内存浪费
//创建一个初始化容量默认为16的byte[]数组(字符串缓冲区对象,StringBuffer)
StringBuffer buffer = new StringBuffer();
//拼接字符串。以后拼接字符串统一调用append()方法
buffer.append("aa");
buffer.append(10);
buffer.append(true);
buffer.append(3.14);
buffer.append(100L);
buffer.append('d');
//输出一个引用,自动调toString()方法
System.out.println(buffer);
//String存储字符串用的byte[] value是有final修饰的,赋值后不可改变的
//而StringBuffer存储字符串用的byte[] value是没有用final修饰的,可以进行追加字符串,满了会自动扩容
//因为数组的扩容效率较低,所以在初始化一个StringBuffer对象时应传一个容量参数
//预估一下需要的大小,减少自动扩容的次数
//上面测试打印已知buffer存的字符串:aa10true3.14100d
//因为StringBuffer也是用来存字符串的,所以很多方法都是和String的方法一样的使用
//StringBuffer的charAt(int index)跟String的charAt(int index)一样的用法
System.out.println(buffer.charAt(0)); //输出:a
System.out.println(buffer.charAt(15)); //输出:d
//System.out.println(buffer.charAt(16)); //报错:StringIndexOutOfBoundsException,下标越界
//StringBuffer的capacity()方法,length(),都是返回所存字符串的长度
System.out.println(buffer.capacity()); //输出:16
System.out.println(buffer.length()); //输出:16
}
}
4、StringBuilder对象的使用
还有一个类也可以完成字符串拼接的问题,用法和功能跟StringBuffer差不多。
这个类就是StringBuilder。
那StringBuffer和StringBuilder有什么区别吗?
通过翻阅它们的源代码可知:
StringBuffer中的方法都带有:synchronized关键字。表示在多线程环境下运行是安全的。
StringBuilder中的方法都没有带synchronized关键字,表示多线程环境下运行是不安全的。
总结:
StringBuffer是线程安全的,StringBuild是非线程安全的。
测试代码和上面一样的使用:
public class Test01 {
public static void main(String[] args) {
//创建一个初始化容量默认也是为16的byte[]数组(字符串缓冲区对象,StringBuild)
StringBuilder builder = new StringBuilder();
//拼接字符串。以后拼接字符串统一调用append()方法
builder.append("aa");
builder.append(10);
builder.append(true);
builder.append(3.14);
builder.append(100L);
builder.append('d');
//输出一个引用,自动调toString()方法
System.out.println(builder);
}
}
总结:
1、StringBuffer,字符串缓冲区对象,也是一个用来存字符串的对象,常用于字符串的拼接。
2、StringBuffer中存储字符串的byte[] value是不带final修饰符,而String里存储字符串的byte[] value是带了final修饰符的。
3、StringBuffer使用无参数构造方法时默认创建长度为16的byte[] value来存储字符串,长度不够时底层会自动扩容。
4、数组的扩容效率是不高的,所以我们使用时应该使用有参数的构造方法,预估一下需求需要的长度,减少自动扩容的次数,提高程序效率。
5、StringBuilder用法跟StringBuffer类似。
6、StringBuffer是线程安全的,StringBuild是非线程安全的。
7、StringBuild使用较多,虽然线程不安全,但有其他解决办法。