String、StringBuffer、StringBuilder 的區別?String爲什麼是不可變的?
String、StringBuffer與StringBuffer區別
String是字符串常量
StringBuffer和StringBuilder是字符串變量
有時候大家會很疑惑,爲什麼String會是常量,如下代碼:
String s = "abcd";
s = s+1;
System.out.print(s);// result : abcd1
僅僅從視覺上來看,s確實改變了,實際上這裏需要大家區分引用和實體對象的概念,第1行,s是String對象的一個引用,指向”abcd”這個String對象,我們這裏說的常量意思是String對象的字面值不能改變,而第二行s+1又創建出了一個String對象用來存儲新的字面值,然後s重新指向這個新的對象。
而StringBuffer,StringBuffer的值是可以改變的。
StringBuffer是線程安全的,也就是多線程修改同一個StringBuffer對象的時候,過程是同步的,當然這就導致了StringBuffer的效率降低,畢竟如果要提升安全性,就必須要損失一定的效率。
StringBuilder是jdk1.5後新增的,主要就是爲了提升單線程下StringBuffer的效率問題,因爲StringBuilder沒有了同步操作,所以效率提升了。
從以下源碼中也可以看出就是多了一個synchronized 的區別。
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, Appendable, CharSequence
{
/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
public synchronized StringBuffer append(int i) {
super.append(i);
return this;
}
public synchronized StringBuffer delete(int start, int end) {
super.delete(start, end);
return this;
}
}
public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, Appendable, CharSequence {
public StringBuilder() {
super(16);
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
}
}
String,StringBuffer與StringBuilder速度區別
從執行效率快慢來看
String < StringBuffer < StringBuilder
但是存在一種特殊情況,就是當String全是字面量相加的時候,這種情況會很快,因爲字面量在編譯期時,編譯器會優化處理,將字面量全部合成一個字面量然後扔進方法區的常量池中,所以運行時當在執行S1指向的時候,這個對象就已經存在與常量池中了,不需要計算了。而StringBuffer 則需要在運行時進行append操作,所以這就造成了這種假象。
常量池可以參看《Java常量池理解》這篇文章。
//String效率是遠要比StringBuffer快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“simple”).append(“ test”);
把上面代碼換成下面代碼,String的執行效率就低了很多,因爲運行時需要重新創建一個對象,將S2,S3 ,S4的值相加厚再複製給這個新對象,S1再重新指向這個新對象。
//String速度是非常慢的:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
String爲什麼是不可變的?
先上源代碼:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
...
...
}
String類使用了final修飾,那麼使用了final修飾就規定了String是不能被繼承的,換句話說,有一個String s=”abc”,s引用我們可以很明確的知道s就是指向的String類型的對象,而不是String類型的子類,這樣從jvm的角度考慮,是提升了一定的效率,而且可以看到char value[]也是final,這說明了裏面的char數組也是不能改變的,只能進行一次賦值,而且我們都知道數組一旦長度固定,就沒有辦法擴容,所以這就是爲什麼String對象裏面的值不能改變的原因,因爲String對象一旦創建,char數組的長度就剛好夠存字符串的長度,以後就沒有辦法擴充了。