Java中的String、StringBuffer与StringBuilder
之前对这三中字符串类只有很少的了解,现在大致了解了下它们之间的差别:
- String - - - - - - - - - - - - - - 字符串常量
- StringBuffer - - - - - - - - - - 字符串变量(线程安全)
- StringBuilder - - - - - - - - - 字符串变量(非线程安全)
1. String
String类被final修饰,也就是说String对象是不可变的。String 是一个常量,他的值在创建之后不能改变,字符串缓冲区支持修改,因为字符串对象是不可变的,所以支持共享。
String s="aaaa";
System.out.println("s="+a);
s="bbbb";
System.out.println("s="+a);
这段代码打印结果:
s=aaaa
s=bbbb
看似对象s产生了变化,s=”bbbb“;这句代码实际上生成一个新的对象,并且s指向新的对象,”aaaa“失去引用。String是由一个final修饰的字符数组实现的,它的很多改变本身的方法都是new了一个新的对象,例如常用的substring:
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
但是String对象也并非是完全没法修改的,我们可以通过Java的反射机制修改,但是这是不推荐的。
2. StringBuffer与StringBuilder
StringBuffer 是个可变的对象,就是每次操作都是对对象本身进行操作,而不用生成新的对象,这样效率肯定就会有有很大的提高,在大部分情况下StringBuffer的效率要比String类型要高。
StringBuilder 与StringBuffer一样是个可变的字符序列,提供与StringBuffer兼容的API,但是不能保证同步,用在字符串缓冲区被当个线程使用的情况,在单机非多线程的情况下使用StringBuilder会有比较好的效率,因为StringBuilder没有处理同步(Synchronized)问题。StringBuffer则会处理同步问题,如果StringBuilder会在多线程下被操作,则要改用StringBuffer,让对象自行管理同步问题。
注意点:
在使用StringBuffer时指定其容量,会比不指定其容量要快40%到50%左右,甚至比不指定容量的StringBuilder要快。因为StringBuffer内部实现是char数组,默认初始化长度是16,每当字符串长度大于char数组的初始化长度时,JVM会构造更大的新数组,并将原来的数组复制到新数组中去,提前指定其容量避免了复制数组的开销。所以在使用时最好指定其容量。这是一个良好的编程习惯,对于性能有很大的提升。
避免使用“+=”操作符来构造字符串,因为这会生成新对象。应该使用append方法。String在少量变化的字符串时使用,StringBuffer在大量多线程的时候使用,StringBuilder在大量单线程的环境中使用较好。