String StringBuffer 和 StringBuilder 的区别是什么?
【1】可变性
String类中使用 final 关键字修饰字符数组来保存字符串,privatefinal char value[],所以String对象是不可变的。
在 Java 9 之后,String、StringBuilder与StringBuffer的实现改用 byte 数组存储字符串
privatefinal byte[] value
为什么使用byte字节而舍弃了char字符?
节省内存占用,byte占一个字节(8位),char占用2个字节(16),相较char节省一半的内存空间。节省gc压力。
针对初始化的字符,对字符长度进行判断选择不同的编码方式。如果是 LATIN-1 编码,则右移0位,数组长度即为字符串长度。而如果是 UTF16 编码,则右移1位,数组长度的二分之一为字符串长度。
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串char[] value,但是没有用final关键字修饰,所以这两种对象都是可变的。
StringBuilder与StringBuffer的构造方法都是调用父类构造方法,也就是AbstractStringBuilder实现的,查阅源码。
abstract class AbstractStringBuilder implements Appendable, CharSequence {/*** The value is used for character storage.*/char[] value;/*** The count is the number of characters used.*/int count;/*** This no-arg constructor is necessary for serialization of subclasses.*/AbstractStringBuilder() {}/*** Creates an AbstractStringBuilder of the specified capacity.*/AbstractStringBuilder(int capacity) {value = new char[capacity];}}
【2】线程安全性
String中的对象不可改变的,也可以理解为常量,线程安全。
AbstractStringBuilder类是StringBuilder与StringBuffer都的公共父类,定义了一些字符串的基本操作/公共方法。
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以线程是安全的。
StringBuilder并没有对方法进行加同步锁,所以线程是不安全的。
【3】性能
每次对String类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String对象。
StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。
相同情况下使用StringBuilder相比使用StringBuffer仅能获得10%~15%左右的性能提升,但是却要冒多线程不安全的风险。
【4】总结
操作少量的数据: 适用String单线程操作字符串缓冲区下操作大量数据: 适用StringBuilder多线程操作字符串缓冲区下操作大量数据: 适用StringBuffer