StringBuilder/StringBuffer类
1.字符串拼接问题
存在问题:
由于String类的对象内容不可改变, 所以每当进行字符串拼接时, 总是会在内存中创建一个新的对象。
如:
//String类的对象内容不可改变,下面总共产生了三个字符串
String s = "Hello";
s += "World";
System.out.println(s);
2个字符串相加, 在字符串常量池中创建了3个字符串,“Hello”、“World”、“HelloWorld”。3个字符串相加, 会创建5个字符串…以此类推, 用这种方式进行字符串拼接效率低下。
解决方法:
java.lang.StringBuilder 字符串缓冲区
StringBuilder类的对象底层也是一个数组, 但是没有被final修饰, 可以改变长度
StringBuilder类的对象是个变量, 进行字符串拼接时不用创建新的对象, 效率更高, 如果超出了容量, 会自动扩容
byte[] value = new byte[16];
java.lang.StringBuffer跟 StringBuilder十分相似
2.构造方法
根据API文档, StringBuilder类的常用构造方法有2个:
- public StringBuilder() : 构造一个空的StringBuilder容器。
- public StringBuilder(String str) : 构造一个StringBuilder容器, 并将字符串添加进去。
3.常用方法
- public StringBuilder append(…) : 添加任意类型数据的字符串形式, 并返回当前对象本身。
- public String toString(): 将当前StringBuilder对象转换为String对象。
- public StringBuilder insert(int offset, Object obj) : 将对象插入指定索引位置,并返回当前对象本身
- public StringBuilder reverse() : 反转字符串内容
public class testStringBuilder {
public static void main(String[] args) {
//String类的对象内容不可改变,下面总共产生了三个字符串
String s = "Hello";
s += "World";
System.out.println(s);
System.out.println("下面是StringBuilder类==================================");
/**
* StringBuilder类
* 构造方法:
* - public StringBuilder() : 构造一个空的StringBuilder容器。
* - public StringBuilder(String str) : 构造一个StringBuilder容器, 并将字符串添加进去。
* - public StringBuilder insert(int offset, Object obj) : 将对象插入指定索引位置,并返回当前对象本身
*/
StringBuilder sbd1 = new StringBuilder();
StringBuilder sbd2 = new StringBuilder("abc");
sbd1 = sbd1.append("123");//字符串拼接
sbd1 = sbd1.append(sbd2);
System.out.println(sbd1);
sbd1.insert(1,0);//在指定索引位置插入对象
System.out.println(sbd1);
String str = sbd1.toString();//把StringBuilder对象转换为String对象
System.out.println(str);
System.out.println("下面是StringBuffer类==================================");
/**
* StringBuffer类,常用方法的使用跟StringBuilder类相同
*/
StringBuffer sbf1 = new StringBuffer();
StringBuffer sbf2 = new StringBuffer("abc");
sbf1 = sbf1.append("123");//字符串拼接
sbf1 = sbf1.append(sbf2);
System.out.println(sbf1);
sbf1.insert(1,0);//在指定索引位置插入对象
System.out.println(sbf1);
String str1 = sbf1.toString();//把StringBuffer对象转换为String对象
System.out.println(str1);
/**
* 链式编程:方法的返回值是一个对象,可以根据对象继续调用方法
*/
sbd1.append(1).append(2).append(3).append(4);
}
}
扩展-StringBuilder、StringBuffer、String区别
以下引用自<java中String、StringBuffer和StringBuilder的区别(简单介绍)>[https://www.cnblogs.com/weibanggang/p/9455926.html]
概况
三者共同之处:都是final类,不允许被继承,主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着,且考虑到防止其中的参数被参数修改影响到其他的应用。
StringBuffer是线程安全,可以不需要额外的同步用于多线程中;
StringBuilder是非同步,运行于多线程中就需要使用着单独同步处理, 但是速度就比StringBuffer快多了;
StringBuffer与StringBuilder两者共同之处: 可以通过append、insert进行字符串的操作。
String实现了三个接口:Serializable、Comparable、CarSequence
StringBuilder只实现了两个接口Serializable、CharSequence,相比之下String的实例可以通过compareTo方法进行比较,其他两个不可以。
运行速度区别
一般情况下由快到慢: StringBuilder > StringBuffer > String
String最慢的原因:String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。
而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。
另外,有时候我们会这样对字符串进行赋值
String str=“abc”+“de”;
这样String的速度比使用StringBuilder拼接的运行速度要快很多, 这是JVM虚拟机编译优化的结果。虚拟机在编译阶段直接将右侧字符串拼接完成, 运行阶段只是单纯的赋值过程, 相当于 String str=“abcde”; 所以速度很快。
线程安全区别
在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的
如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
缓冲区
以下引用自<StringBuffer 和 StringBuilder 的 3 个区别>https://segmentfault.com/a/1190000017909550
StringBuffer 代码片段:
private transient char[] toStringCache;
@Override
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
StringBuilder 代码片段:
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
可以看出,StringBuffer 调用toString()方法需要使用缓存区的 toStringCache 拷贝一次字符数组, 再构造一个字符串。
而 StringBuilder 则直接通过字符数组构造一个字符串。
这也是对 StringBuffer 缓冲区的一个优化,而且StringBuffer 的这个toString 方法仍然是同步的。
总结
String:适用于少量的字符串操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况