1. 程式人生 > >【每日一學190727】stringBuilder和stringBuffer的區別

【每日一學190727】stringBuilder和stringBuffer的區別

String

  • 從概念上來講字串就是unicode字元序列,java並沒有內建的字串型別,是在標準的java類庫

    簡單來講就是Java 官方為開發者提供了很多功能強大的類,這些類被分別放在各個包中,隨JDK一起釋出,稱為Java類庫或Java API。

    中提供了一個預定義類,叫做String,每一個用雙引號括起來的字串都是String類的一個例項。

  • string是不可變字串,也就是說String物件建立後不能被修改,是不可變的,所謂的修改其實是建立了一個新的物件,所指向的記憶體空間不同。所以當我們修改一個字串的時候其實是新建立了一個字串物件,但是不可變字串有一個優點:編譯器可以讓字串共享

    。看下面的程式碼

    	public static void main(String[] args) {
        String  s1 = "hello";
        String  s2 = "hello";
        String  s3 = new String("hello");
        String  s4 = new String("hello");
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
        System.out.println(s3 == s4);
    }
    

    結果是:

    	true
    	false
    	false
    

    在記憶體中它們的存放關係引用圖如下:

    • 一旦一個字串在記憶體中建立,則這個字串就不可變。
    • 字串常量出現多次時會被編譯器優化,只建立一個物件,就像上面的s1與s2都是指向同一個字串常量,也就是相同的物件,所以他們所指向的物件的記憶體地址相同。
    • 只要使用了new關鍵字就會創生一個新的物件,即使他們的內容是相同的。
    • == 號比較的是兩個物件的記憶體地址是否一致,所以比較兩個字串時需要使用equals,來進行內容的比較。

注:由於字串的不可變性,所以在字串拼接時會產生很多的無用的中間的物件,如果頻繁的進行這樣的操作可能會對效能有所影響。

stringBuilder與StirngBuilder

上面已經說了如果使用string的話,那麼當有很多字串拼接的時候就會中產生很多無用的中間物件,此時就可以使用StringBuffer與StringBuilder來解決這個問題了。 他們底層其實是使用 System.arraycopy(char dst[], int, char dst[], int, int);這樣的一個數組拷貝的方式來實現字串的動態改變值。

StringBuffer和StringBuilder的區別

比如通過append(str)這個方法來比較一下stringBuffer與stringBuilder的區別,

stringBuffer

public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

stringBuilder

public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

可以看到stringBuffer裡面的方法加上了synchronized關鍵字來保證執行緒安全,對應其他修改資料的方法也是一樣的,就是StringBuffer與StringBuilder的主要區別就是StringBuffer是執行緒安全的,StringBuilder去掉了執行緒安全,其餘的是一樣的。

編譯器對string型別的優化

String s1 = "helloWorld";
String s2 = "hello" + "World";
String s3 = "hello";
String s4 = s3 + "World";
System.out.println(s1 == s2);
System.out.println(s1 == s4);

結果

true
false

因為“hello” + “World” 在編譯器其實就被優化成了"helloWorld",在執行期間他們是指向同一個常量池中的同一個物件,但是s4是變數與常量相加的,在編譯期是s3只是一個變數,而不是一個常量,所以在執行期得到的物件其實是一個新的物件。

String a = "helloWorld";
final String b = "hello";
String c = b + "World";
System.out.println((a == c));

結果

true

對於被final修飾的變數,會在class檔案常量池中儲存一個副本,也就是說不會通過連線而進行訪問,對final變數的訪問在編譯期間都會直接被替代為真實的值。

總體來看:

  • 如果字串常量不經常改變的話就使用String,這是比較快速高效的
  • 在單執行緒中,並且有大量的字串修改,那麼就可以使用stringBuilder
  • 在多執行緒中如果有大量的字串操作那麼就使