字符串是java中最常用的数据类型,对于字符串,jdk里有3个类来表示:String、StringBuilder、StringBuffer。其中,String用的最多,StringBuilder次之,StringBuffer最少。今天复习一下这三个类。
String
String类使用char[]来表示字符串,其引用value被final修饰,不可改变。
String类被final关键字修饰,不可继承,那么类中的方法也不能被覆盖,它本身也没有提供修改char[]的方法,因此,我们通常认为String是不可变的。
对String类的每一次运算,都会生成新的字符串,比如:String s = "a"+"b",在内存中会有3个字符串:"a" 、"b"、 "ab"。因此在循环中对大量字符串进行“加”操作,会造成空间浪费。
StringBuilder和StringBuffer
这两个可以放一起,因为它们都继承自AbstractStringBuilder。AbstractStringBuilder也是用char[]表示字符串,放在value字段上,没有被final修饰,它是可变的。我们可以通过修改char[]来改变字符串。AbstractStringBuilder提供了很多字符串操作方法,其中最常用的是 append方法,表示字符串的拼接操作,也就是“加”。在创建StringBuilder或StringBuffer对象时,可以指定char[]的初始长度,如果没有指定,则默认为16。每次调用append时,都会判断字符数组的长度是否够用,不够则进行扩容,扩容时会创建新的字符数组,并把原数组里的字符copy进去,再使value指向新数组。所以,在初始化时,我们可以选择合适的数组长度,来减少扩容次数,或许可以提升一点点性能。
StringBuilder继承了AbstractStringBuilder,并且几乎没有扩展父类的功能,只是对父类方法简单覆盖。在对char数组进行修改、读取时,没有考虑并发问题,因此它是非线程安全的。
StringBuffer也没有扩展父类的功能,但是它在覆盖父类方法时,在涉及线程安全的方法上添加了synchronized关键字,使其在并发操作时变得线程安全,但同时也损失了一点性能。
总结
在大多数场景下,使用String就行;
在大量字符串拼接操作的场景下,尽量使用StringBuilder;
在需要并发操作可变字符串的场景下,使用StringBuffer,这种场景比较少,也容易被StringBuilder+同步替代。