1. 程式人生 > >JAVA的String、StringBuilder和StringBuffer類的區別

JAVA的String、StringBuilder和StringBuffer類的區別

StringBuffer類(或者StringBuilder)和String一樣,也用來代表字串,只是由於StringBuffer的內部實現方式和String不同,所以StringBuffer在進行字串處理時,不生成新的物件,在記憶體使用上要優於String類。

所以在實際使用時,如果經常需要對一個字串進行修改,例如插入、刪除等操作,使用StringBuffer要更加適合一些。

在StringBuffer類中存在很多和String類一樣的方法,這些方法在功能上和String類中的功能是完全一樣的。

但是有一個最顯著的區別在於,對於StringBuffer物件的每次修改都會改變物件自身,這點是和String類最大的區別。

另外由於StringBuffer是執行緒安全的,關於執行緒的概念後續有專門的章節進行介紹,所以在多執行緒程式中也可以很方便的進行使用,但是程式的執行效率相對來說就要稍微慢一些。

1、StringBuffer物件的初始化

StringBuffer物件的初始化不像String類的初始化一樣,Java提供的有特殊的語法,而通常情況下一般使用構造方法進行初始化。
例如:

     StringBuffer s = new StringBuffer();

這樣初始化出的StringBuffer物件是一個空的物件。
如果需要建立帶有內容的StringBuffer物件,則可以使用:
StringBuffer s = new StringBuffer(“abc”);
這樣初始化出的StringBuffer物件的內容就是字串”abc”。
需要注意的是,StringBuffer和String屬於不同的型別,也不能直接進行強制型別轉換,下面的程式碼都是錯誤的:

StringBuffer s = “abc”;        //賦值型別不匹配
tringBuffer s = (StringBuffer)”abc”; //不存在繼承關係,無法進行強轉
StringBuffer物件和String物件之間的互轉的程式碼如下:
         String s = “abc”;
         StringBuffer sb1 = new StringBuffer(“123”);
         StringBuffer sb2 = new StringBuffer(s);   //String轉換為StringBuffer
         String s1 = sb1.toString();              //StringBuffer轉換為String

2、StringBuffer的常用方法

StringBuffer類中的方法主要偏重於對於字串的變化,例如追加、插入和刪除等,這個也是StringBuffer和String類的主要區別。
a、append方法
public StringBuffer append(boolean b)
該方法的作用是追加內容到當前StringBuffer物件的末尾,類似於字串的連線。呼叫該方法以後,StringBuffer物件的內容也發生改變,例如:
StringBuffer sb = new StringBuffer(“abc”);
sb.append(true);
則物件sb的值將變成”abctrue”。
使用該方法進行字串的連線,將比String更加節約內容,例如應用於資料庫SQL語句的連線,例如:

StringBuffer sb = new StringBuffer();
String user = “test”;
String pwd = “123”;
sb.append(“select * from userInfo where username=“)
          .append(user)
          .append(“ and pwd=”)
          .append(pwd);

這樣物件sb的值就是字串“select * from userInfo where username=test and pwd=123”。

b、deleteCharAt方法
public StringBuffer deleteCharAt(int index)
該方法的作用是刪除指定位置的字元,然後將剩餘的內容形成新的字串。例如:

StringBuffer sb = new StringBuffer(“Test”);
sb. deleteCharAt(1);

該程式碼的作用刪除字串物件sb中索引值為1的字元,也就是刪除第二個字元,剩餘的內容組成一個新的字串。所以物件sb的值變為”Tst”。
還存在一個功能類似的delete方法:
public StringBuffer delete(int start,int end)
該方法的作用是刪除指定區間以內的所有字元,包含start,不包含end索引值的區間。例如:

StringBuffer sb = new StringBuffer(“TestString”);
sb. delete (1,4);

該程式碼的作用是刪除索引值1(包括)到索引值4(不包括)之間的所有字元,剩餘的字元形成新的字串。則物件sb的值是”TString”。
c、insert方法
public StringBuffer insert(int offset, boolean b)
該方法的作用是在StringBuffer物件中插入內容,然後形成新的字串。例如:

StringBuffer sb = new StringBuffer(“TestString”);
sb.insert(4,false);

該示例程式碼的作用是在物件sb的索引值4的位置插入false值,形成新的字串,則執行以後物件sb的值是”TestfalseString”。
d、reverse方法

public StringBuffer reverse()

該方法的作用是將StringBuffer物件中的內容反轉,然後形成新的字串。例如:

StringBuffer sb = new StringBuffer(“abc”);
sb.reverse();

轉以後,物件sb中的內容將變為”cba”。
e、setCharAt方法

public void setCharAt(int index, char ch)

該方法的作用是修改物件中索引值為index位置的字元為新的字元ch。例如:
StringBuffer sb = new StringBuffer(“abc”);
sb.setCharAt(1,’D’);
則物件sb的值將變成”aDc”。

f、trimToSize方法
public void trimToSize()

該方法的作用是將StringBuffer物件的中儲存空間縮小到和字串長度一樣的長度,減少空間的浪費。
總之,在實際使用時,String和StringBuffer各有優勢和不足,可以根據具體的使用環境,選擇對應的型別進行使用。

String和StringBuffer的效率對比

為了更加明顯地看出它們的執行效率,下面的程式碼,將26個英文字母加了10000次。

public class Demo {
    public static void main(String[] args){
        String fragment = "abcdefghijklmnopqrstuvwxyz";
        int times = 10000;
    // 通過String物件
        long timeStart1 = System.currentTimeMillis();
        String str1 = "";
        for (int i=0; i<times; i++) {
        str1 += fragment;
        }
        long timeEnd1 = System.currentTimeMillis();
        System.out.println("String: " + (timeEnd1 - timeStart1) +     "ms");
    // 通過StringBuffer
        long timeStart2 = System.currentTimeMillis();
        StringBuffer str2 = new StringBuffer();
        for (int i=0; i<times; i++) {
            str2.append(fragment);
        }
        long timeEnd2 = System.currentTimeMillis();
        System.out.println("StringBuffer: " + (timeEnd2 - timeStart2) + "ms");
    }
}

執行結果:

String: 5287ms
StringBuffer: 3ms

結論很明顯,StringBuffer的執行效率比String快上千倍,這個差異隨著疊加次數的增加越來越明顯,當疊加次數達到30000次的時候,執行結果為:
String: 35923ms
StringBuffer: 8ms

所以,強烈建議在涉及大量字串操作時使用StringBuffer。

StringBuilder類

StringBuilder類和StringBuffer類功能基本相似,方法也差不多,主要區別在於StringBuffer類的方法是多執行緒安全的,而StringBuilder不是執行緒安全的,相比而言,StringBuilder類會略微快一點。

StringBuffer、StringBuilder、String中都實現了CharSequence介面。

CharSequence是一個定義字串操作的介面,它只包括length()、charAt(int index)、subSequence(int start, int end) 這幾個API。

StringBuffer、StringBuilder、String對CharSequence介面的實現過程不一樣,如下圖所示:
這裡寫圖片描述
可見,String直接實現了CharSequence介面;StringBuilder 和 StringBuffer都是可變的字元序列,它們都繼承於AbstractStringBuilder,實現了CharSequence介面。

jdk的實現中StringBuffer與StringBuilder都繼承自AbstractStringBuilder,對於多執行緒的安全與非安全看到StringBuffer中方法前面的一堆synchronized就大概瞭解了。

這裡寫圖片描述

這裡寫圖片描述

我們知道使用StringBuffer等無非就是為了提高java中字串連線的效率,因為直接使用+進行字串連線的話,jvm會建立多個String物件,因此造成一定的開銷。
AbstractStringBuilder中採用一個char陣列來儲存需要append的字串,char陣列有一個初始大小,當append的字串長度超過當前char陣列容量時,則對char陣列進行動態擴充套件,也即重新申請一段更大的記憶體空間,然後將當前char陣列拷貝到新的位置,因為重新分配記憶體並拷貝的開銷比較大,所以每次重新申請記憶體空間都是採用申請大於當前需要的記憶體空間的方式,這裡是2倍。

分類總結如下:
(1)StringBuffer在進行追加操作的時候,只是在字串的後邊進行追加操作,追加的過程也是需要進行判斷預存陣列大小是否超過一開始設定的16子字元,然後才可以進行追加,每次結果都會對 StringBuffer 物件本身進行操作,而不是生成新的物件,再改變物件引用。;由於StringBuilder和StringBuffer本身都是繼承自AbstractStringBuilder,在進行追加操作的時候,使用的就是AbstractStringBuilder類中的append方法,下圖中展示了AbstractStringBuilder類中所有過載的append方法,根據不同的需求可以實現不同的功能,
這裡寫圖片描述

以append(CharSequence s)為例,展示一下:(下邊的方法都是AbstractStringBuilder中的方法)

@Override
    public AbstractStringBuilder append(CharSequence s) {
        if (s == null)
            return appendNull();
        if (s instanceof String)
            return this.append((String)s);
        if (s instanceof AbstractStringBuilder)
            return this.append((AbstractStringBuilder)s);

        return this.append(s, 0, s.length());
    }

首先進行判斷是否為空,然後判斷是哪一個例項,最後掉用append另一個過載的方法:

@Override
    public AbstractStringBuilder append(CharSequence s, int start, int end) {
        if (s == null)
            s = "null";
        if ((start < 0) || (start > end) || (end > s.length()))
            throw new IndexOutOfBoundsException(
                "start " + start + ", end " + end + ", s.length() "
                + s.length());
        int len = end - start;
        ensureCapacityInternal(count + len);
        for (int i = start, j = count; i < end; i++, j++)
            value[j] = s.charAt(i);
        count += len;
        return this;
    }

其中:

    /**
     * The count is the number of characters used.
     */
    int count;

    /**
     * The value is used for character storage.
     */
    char[] value;

可以看出:ensureCapacityInternal(count + len); 是一個擴容的過程,value[j] = s.charAt(i); 是儲存追加字串的過程,具體的過程就是再原StringBuffer物件的基礎上首先通過擴容,之後在進行追加操作;

(2)StringBuffer的四個構造方法如下:

StringBuffer() 
構造一個其中不帶字元的字串緩衝區,其初始容量為 16 個字元。

StringBuffer(CharSequence seq)  
public java.lang.StringBuilder(CharSequence seq) 構造一個字串緩衝區,它包含與指定的 CharSequence 相同的字元。

StringBuffer(int capacity)   
構造一個不帶字元,但具有指定初始容量的字串緩衝區。

StringBuffer(String str)  
構造一個字串緩衝區,並將其內容初始化為指定的字串內容

每個字串緩衝區都有一定的容量。只要字串緩衝區所包含的字元序列的長度沒有超出此容量,就無需分配新的內部緩衝區陣列。如果內部緩衝區溢位,則此容量自動增大。從 JDK 5 開始,為該類補充了一個單個執行緒使用的等價類,即 StringBuilder。與該類相比,通常應該優先使用 StringBuilder 類,因為它支援所有相同的操作,但由於它不執行同步,所以速度更快。

(3)而對於String來說,雖然追加(字串串聯)的本質也是通過建立StringBuilder物件,通過StringBuilder的append方法來實現的,但是每次追加的過程都是一次建立StringBuilder物件的過程,因也就是說在每次對 String 型別進行改變的時候其實都等同於生成了一個新的 String 物件,然後將指標指向新的 String 物件,效率顯然要比直接使用StringBuilder來說要低很多,網上也有很多測試的實驗,也充分說明這一點,所以經常改變內容的字串最好不要用 String ,因為每次生成物件都會對系統性能產生影響,特別當記憶體中無引用物件多了以後, JVM 的 GC 就會開始工作,那速度是一定會相當慢的;

(4)而在某些特別情況下, String 物件的字串拼接其實是被 JVM 解釋成了 StringBuffer 物件的拼接,所以這些時候 String 物件的速度並不會比 StringBuffer 物件慢,而特別是以下的字串物件生成中, String 效率是遠要比 StringBuffer 快的:

String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);

會很驚訝的發現,生成 String S1 物件的速度簡直太快了,而這個時候StringBuffer 居然速度上根本一點都不佔優勢。其實這是 JVM 的一個把戲,在JVM 眼裡,這個String S1 = “This is only a” + “ simple” + “test”;
其實就是: String S1 = “This is only a simple test”;
所以當然不需要太多的時間了。但大家這裡要注意的是,如果你的字串是來自另外的 String 物件的話,速度就沒那麼快了,譬如:

String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;

這時候 JVM 會規規矩矩的按照原來的方式去做, S1 物件的生成速度就不像剛才那麼快了,一會兒我們可以來個測試作個驗證。
由此我們得到第一步結論: 在大部分情況下 StringBuffer > String

(4)總的來說,StringBuilder適合於需要進行經常性的字元追加刪除操作等,String本身設計的初衷應該是為了在後邊的使用過程種,不會進行太多的增刪操作,畢竟String是final型別的,是不可變的物件,因此他們都有所擅長的地方,根據自己的需求進行合理的選擇即可;

總結

執行緒安全:
StringBuffer:執行緒安全
StringBuilder:執行緒不安全

速度:
一般情況下,速度從快到慢為 StringBuilder > StringBuffer > String,當然這是相對的,不是絕對的。

使用環境:
操作少量的資料使用 String;
單執行緒操作大量資料使用 StringBuilder;
多執行緒操作大量資料使用 StringBuffer。

相關推薦

JAVA的StringStringBuilderStringBuffer區別

StringBuffer類(或者StringBuilder)和String一樣,也用來代表字串,只是由於StringBuffer的內部實現方式和String不同,所以StringBuffer在進行字串處理時,不生成新的物件,在記憶體使用上要優於String類。

StringStringBuilderStringBuffer

attr substring 匹配 忽略 ren set area all position html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figur

StringStringBuilderStringBuffer區別用法

分別使用使用這三種來拼接字串,對比各自損耗的時間: 經過測試: package com.test; public class Main{ public static void main(String[] args){ testString(); testStrin

StringStringBuilderStringBuffer區別

1         String、StringBuilder和StringBuffer的區別 String內部是通過char陣列來儲存資料的,類的操作方法substr、replace等都需要重新new一個新的char陣列來儲存,

Java StringStringBuilderStringBuffer區別

String和StringBuffer主要有2個區別: (1)String類物件為不可變物件,一旦你修改了String物件的值,隱性重新建立了一個新的物件,釋放原String物件,

StringBuffer的使用詳解底層實現StringStringBuffer區別StringBuffer的常用方法

Java StringBuffer類的使用和詳解底層實現、String和StringBuffer的區別、StringBuffer的常用方法 1.java StringBuffer類 2. StringBuffer類的構造器(構造方法) 3.

Java基礎知識之StringStringBuilderStringBuffer三者的區別

String、StringBuilder和StringBuffer這三個類在操作字串時主要有執行速度和執行緒安全這兩方面的區別: 1.執行速度   執行速度,即執行字串操作時程式碼執行的時間快慢,在這方面執行速度快慢為:StringBuilder > StringBuffer >

JDK 1.8 源碼解析 StringStringBuilderStringBuffer的異同

sta his 獲取 對象鎖 創建 實現 buffer enc 字符串   JDK提供了String、StringBuilder和StringBuffer這三個類來處理字符串,其中StringBuilder類是在JDK 1.5中新增的。   不同點如下:   1 是否有父類

StringStringbuilderStringBuffer常用方法

case 位置 string對象 ase system span builder println lsi 1、String類: //根據字符串直接量來創建一個String對象。新創建的對象是該參數字符串的副本。 String s = new String("String

Java中StringbuilderStringBuffer區別

①執行速度。在這方面執行速度快慢為:StringBuilder > StringBuffer > String String最慢的原因: String為字串常量,而StringBuilder和StringBuffer均為字串變數,即String物件一旦建立之後該物件是不可更改

StringStringBuilderStringBuffer區別

    最近學習到StringBuffer,心中有好些疑問,搜尋了一些關於String,StringBuffer,StringBuilder的東西,現在整理一下。 關於這三個類在字串處理中的位置不言而喻,那麼他們到底有什麼優缺點,到底什麼

Java中String,StringBuilderStringBuffer區別

這三個類的主要區別在兩個方面:運算速度(運算效能或執行效率)和執行緒安全性。 1、運算速度比較(通常情況下):StringBuilder > StringBuffer > String String是final類不能被繼承且為字串常量,而StringBuild

StringStringBuilderStringBuffer詳解

以JDK1.8原始碼為例 一、原始碼 String: public final class String implements java.io.Serializable, Comparable<String>, CharSequence { …… }

StringStringBuilderStringBuffer

這三個類之間的區別主要是在兩個方面,即執行速度和執行緒安全這兩方面。 首先說執行速度,或者說是執行速度,在這方面執行速度快慢為:StringBuilder > StringBuffer > String   String最慢的原因:   String為字串常量

StringBuilderStringBuffer區別聯絡

之前剛開始接觸java語言的時候,經常會記憶一下java工具類的特性,但是,時間長了,如果不溫習這些知識,這種知識點的對比,很快會忘記。思考過這個問題,發現還是理解不夠深刻,或者說是印象不太深刻,我覺得jdk的原始碼是一個可以讓人深刻的東西,一起來看一下吧,s

JAVA 中的 StringBuilder StringBuffer區別,適用的場景是什麼?

1.使用String類的場景:在字串不經常變化的場景中可以使用String類,例如常量的宣告、少量的變數運算。 2.使用StringBuffer類的場景:在頻繁進行字串運算(如拼接、替換、刪除等),並且執行在多執行緒環境中,則可以考慮使用StringBuffer,例如XML解析、HTTP引數解析和封裝。

[Java] String, StringBuilder StringBuffer區別

String物件內容不可變, StringBuilder 和 StringBuffer 物件內容可變。 StringBuilder比 StringBuffer效率更高, 但StringBuffer提供執行緒同步,也就是說,如果多個執行緒併發訪問同一個字串,即併

【每日一學190727】stringBuilderstringBuffer區別

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

【扯皮系列】一篇與眾不同的 StringStringBuilder StringBuffer 詳解

## 碎碎念 這是一道老生常談的問題了,字串是不僅是 Java 中非常重要的一個物件,它在其他語言中也存在。比如 **C++、Visual Basic、C# 等**。字串使用 String 來表示,字串一旦被創建出來就不會被修改,當你想修改 StringBuffer 或者是 StringBuilder,出於

Java中的StringBufferStringBuilder包裝器

相對 字母 失敗 這樣的 構造方法 stat float cin 序列 1.如何使用StringBuffer類? 答:1).StringBuffer類用於表示可以修改的字符串,稱為字符串緩沖對象; 2).使用運算符的字符串將自動創建字符串緩沖對象; 例:st