String、StringBuffer、StringBuilder 的區別?String爲什麼是不可變的?

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數組的長度就剛好夠存字符串的長度,以後就沒有辦法擴充了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章