JDK提供了String、StringBuilder和StringBuffer这三个类来处理字符串,其中StringBuilder类是在JDK 1.5中新增的。
不同点如下:
1 是否有父类
String没有父类。
// String类不能被继承
// 实现了Serializable、Comparable和CharSequence(字符序列)接口
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
StringBuilder和StringBuffer都继承了抽象类AbstractStringBuilder。
// 抽象类AbstractStringBuilder
// 实现了Appendable(可追加)和CharSequence(字符序列)接口
abstract class AbstractStringBuilder implements Appendable, CharSequence
1 // StringBuilder类不能被继承
2 // 继承了抽象类AbstractStringBuilder
3 // 实现了Serializable和CharSequence接口
4 public final class StringBuilder
5 extends AbstractStringBuilder
6 implements java.io.Serializable, CharSequence
1 // StringBuffer类不能被继承
2 // 继承了抽象类AbstractStringBuilder
3 // 实现了Serializable和CharSequence接口
4 public final class StringBuffer
5 extends AbstractStringBuilder
6 implements java.io.Serializable, CharSequence
2 可变性
属性字符数组不可变(数组引用不可变,数组元素可变),String不可变,对于每个不同的字符串都需要一个单独的String对象。
// 字符数组
private final char value[];
AbstractStringBuilder中的字符数组可变,StringBuilder和StringBuffer可变。StringBuilder和StringBuffer都有insert()插入方法、delete()删除方法和append()末尾追加方法,调用System.arraycopy()方法来实现数组元素的拷贝。
// 字符数组
char[] value;
3 是否线程安全
String对象不可变,本质上是线程安全的。StringBuilder和StringBuffer的方法实现大致相同,不同之一是StringBuffer类的方法上加了synchronized关键字,即加了对象锁,该锁会锁住整个对象,效率低。也就是说,StringBuffer是线程安全的。
// 获取子串顺序下从某位置开始首次出现的位置
@Override
public int indexOf(String str, int fromIndex) {
return super.indexOf(str, fromIndex);
}
@Override
public synchronized int indexOf(String str, int fromIndex) {
return super.indexOf(str, fromIndex);
}
相同点如下:
1 substring()方法(截取字符串,即获取子串)
String中的substring()方法:
1 // 截取字符串
2 public String substring(int beginIndex, int endIndex) {
3 if (beginIndex < 0) { // 如果起始下标<0
4 throw new StringIndexOutOfBoundsException(beginIndex);
5 }
6 if (endIndex > value.length) { // 如果末尾下标>字符数组长度
7 throw new StringIndexOutOfBoundsException(endIndex);
8 }
9 int subLen = endIndex - beginIndex; // 获取截取长度
10 if (subLen < 0) { // 如果截取长度<0
11 throw new StringIndexOutOfBoundsException(subLen);
12 }
13 return ((beginIndex == 0) && (endIndex == value.length)) ? this
14 : new String(value, beginIndex, subLen);
15 }
AbstractStringBuilder中的substring()方法:
1 // 获取子串,返回String对象的引用
2 public String substring(int start, int end) {
3 if (start < 0) // 如果开始位置<0
4 throw new StringIndexOutOfBoundsException(start);
5 if (end > count) // 如果结束位置>count
6 throw new StringIndexOutOfBoundsException(end);
7 if (start > end) // 如果开始位置>结束位置
8 throw new StringIndexOutOfBoundsException(end - start);
9 // 返回String对象的引用
10 return new String(value, start, end - start);
11 }
substring()方法都是创建新的String对象并返回该对象引用。
总结
String适用于常量,StringBuilder适用于非并发情况下的字符串操作,StringBuffer适用于并发情况下的字符串操作。
参考资料
从Java源码角度彻底理解String,StringBuilder和StringBuffer的区别
《Effective Java 中文版 第2版》 P66-67