Java提供了String、StringBuffer和StringBuilder类来封装字符串,并提供了一系列操作字符串对象的方法。
三者的共同点是都用来封装字符串、都实现了CharSequence接口、底层都使用char[]存储。但是它们之间也存在不同点。
三者部分源码
String部分源码
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { private final char value[]; private int hash; // Default to 0 private static final long serialVersionUID = -6849794470754667710L; private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; public String() { this.value = "".value; } public String(String original) { this.value = original.value; this.hash = original.hash; } public String(char value[]) { this.value = Arrays.copyOf(value, value.length); } public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; } public int indexOf(int ch) { return indexOf(ch, 0); } ... }
StringBuffer部分源码
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence { private transient char[] toStringCache; static final long serialVersionUID = 3388685877147921107L; public StringBuffer() { super(16); } public StringBuffer(int capacity) { super(capacity); } public StringBuffer(String str) { super(str.length() + 16); append(str); } public StringBuffer(CharSequence seq) { this(seq.length() + 16); append(seq); } ... }
StringBuilder部分源码
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence { static final long serialVersionUID = 4383685877147921099L; public StringBuilder() { super(16); } public StringBuilder(int capacity) { super(capacity); } public StringBuilder(String str) { super(str.length() + 16); append(str); } public StringBuilder(CharSequence seq) { this(seq.length() + 16); append(seq); } ... }
1.是否可变?
String 是被 final 修饰的,是不可变的字符序列,是字符串常量,即使调用 String 的concat 方法,也只是把字符串拼接起来,把拼接后的 String 的值赋给新创建的对象。
StringBuffer 和 StringBuilder 是可变的字符序列,是字符串变量,类的对象能够被多次的修改,并且不产生新的未使用对象。
2.线程是否安全?
String中的对象是不可变的,是被final修饰的,是字符串常量,是线程安全的。
StringBuffer对象在缓冲区被多个线程使用时,它的中的方法大都使用了synchronized 关键字进行修饰,加了同步锁,所以是线程安全的。
StringBuilder是jdk5.0新增的,在使用时没有被synchronized 关键字修饰,不能保证线程安全,可能会出现一些操作错误。
AbstractStringBuilder是StringBuilder和StringBuffer的公共父类,定义了一些字符串的基本操作,它们的用法基本相同。
多线程情况下建议使用StringBuffer,单线程建议使用速度较快的StringBuilder。
3.执行效率
StringBuilder最高,StringBuffer次之,String最低。
4.初始化方式
创建String对象时,可以利用构造方法String str = new String("haha")的方式来对其进行初始化,也可以直接用赋值的方式String s = "haha"来进行初始化。而StringBuffer只能使用构造方法StringBuffer sb = new StringBuffer("hahaha")的方式来进行初始化。
5.是否实现了hashCode和equals方法
String实现了equals和hashCode方法,new String("haha").equals(new String("haha"))的结果为true;
而StringBuffer没有实现equals和hashCode方法,new StringBuffer("heihei").equals(new StringBuffer("heihei"))的结果为false。
6.使用场景
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。
然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。 append方法与直接使用+串联相比,减少常量池的浪费。
一般而言,如果要操作少量的数据时,优先使用String类;如果是在单线程下操作大量数据,优先使用StringBuilder类;如果是在多线程下操作大量的数据,优先使用StringBuilder类。