- 可变性:
- String 类中使用 final 关键字字符数组保存字符串,
private final char value[]
,所以 String 对象是不可变的。 - 而 StringBuilder 和 StringBuffer 都继承自 AbstractStringBuilder 类,在AbstractStringBuilder 中也是使用字符数组保存字符串
char[]value
但是没有用 final 关键字修饰,所以这两种对象都是可变的。
StringBuilder 和 StringBuffer 的构造方法都是调用父类的构造方法也就是 AbstractStringBuilder 实现的。
AbstractStringBuilder.java
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
int count;
AbstractStringBuilder() {
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
- 线程安全性:
- String 中的对象是不可变的,也就可以理解为常量,线程安全。
- AbstractStringBuilder 是 StringBuilder 和 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法:
- StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
- StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
- 性能:
- 每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后指针指向新的 String 对象。
- StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒出线程不安全的风险。
对于三者使用的总结:
- 操作少量的数据 = String
- 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
- 多线程操作字符串缓冲区下操作大量数据 = StringBuffer
既然提到了final
,总结下final
:
final 关键字主要用在三个方面:变量、方法、类
- 对于一个 final 变量,如果是基本数据类型的变量,则其数值一旦在初始化后便不能更改;如果是引用类型变量,则对其初始化之后便不能再让其指向另一个对象。
- 当用 final 修饰一个类时,表明这个类不能被继承。final 类中的所有成员方法都会被隐式地指定为 final 方法。
- 使用 final 方法的原因有两个:
- 把方法锁定,以防任何继承类修改它的定义;
- 效率。在早期的 Java 实现版本中,会将 final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 关键字进行这些优化了)。类中所有的 private 方法都隐式地指定为 final。