String与StringBuffer与StringBuilder的区别
1.可变性
String内部的value值是final修饰的,所以它是一个不可变的类,每一次修改String的值的时候,都会产生一个新的对象。
StringBuffer和StringBuilder是一个可变类,字符串的变更不会产生新的对象。
2.线程安全性
String是一个不可变的类,是线程安全的。
StringBuffer也是线程安全的,因为它的每个操作方法里面都用了Synchronized同步关键字。
StringBuilder它不是线程安全的。
所以在多线程环境下,对字符串进行操作,我应该使用StringBuffer。
3.性能方面
String是性能最低的,因为不可变,意味着做字符串拼接或者修改的时候,我们需要重新去创建新的对象以及分配内存。
StringBuffer要比String的性能更高一点,因为它的可变性,意味关字符串可以直接被修改。
StringBuilder性能最高,因为无锁。
4.存储方面
String存储在字符串常量池中。StringBuilder和StringBuffer存储在堆内存空间。
StringBuilder和StringBuffer都是AbstractStringBuilder抽象类的实现类。
源码
String
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Test {
public static void main(String[] args) { String str1 = "a"; String str2 = new String("a"); String strTmp = ""; String str3 = "a" + strTmp; System.out.println(str1.equals(str2)); System.out.println(str1.equals(str3)); System.out.println(str1 == str2); System.out.println(str1 == str3); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| private final char value[]; 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 String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count <= 0) { if (count < 0) { throw new StringIndexOutOfBoundsException(count); } if (offset <= value.length) { this.value = "".value; return; } } if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.value = Arrays.copyOfRange(value, offset, offset+count); }
public String(int[] codePoints, int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count <= 0) { if (count < 0) { throw new StringIndexOutOfBoundsException(count); } if (offset <= codePoints.length) { this.value = "".value; return; } } if (offset > codePoints.length - count) { throw new StringIndexOutOfBoundsException(offset + count); }
final int end = offset + count;
int n = count; for (int i = offset; i < end; i++) { int c = codePoints[i]; if (Character.isBmpCodePoint(c)) continue; else if (Character.isValidCodePoint(c)) n++; else throw new IllegalArgumentException(Integer.toString(c)); }
final char[] v = new char[n];
for (int i = offset, j = 0; i < end; i++, j++) { int c = codePoints[i]; if (Character.isBmpCodePoint(c)) v[j] = (char)c; else Character.toSurrogates(c, v, j++); }
this.value = v; }
|
可以看到内部变量value使用的是final修饰的。
1 2 3
| this.value = Arrays.copyOf(value, value.length);
this.value = Arrays.copyOfRange(value, offset, offset+count);
|
内部同样有
相当于新申请了一块内存空间。
StringBuilder
1 2 3
| public StringBuilder() { super(16); }
|
1 2 3
| AbstractStringBuilder(int capacity) { value = new char[capacity]; }
|
1 2 3 4 5
| @Override public StringBuilder append(String str) { super.append(str); return this; }
|
1 2 3 4 5 6 7 8 9
| public AbstractStringBuilder append(String str) { if (str == null) return appendNull(); int len = str.length(); ensureCapacityInternal(count + len); str.getChars(0, len, value, count); count += len; return this; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) { if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } if (srcEnd > value.length) { throw new StringIndexOutOfBoundsException(srcEnd); } if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); } System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); }
|
发现这里没有使用新的char数组
StringBuffer
1 2 3 4 5 6
| @Override public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; }
|
只是在方法上加了synchronized关键字。