String、StringBuffer、StringBuilder

字符串在開發中經常使用到,但是Java中提供三種字符串操作的類,String、StringBuffer以及StringBuilder,那麼它們有什麼區別以及怎麼使用呢?
從概念上講,Java字符串就是Unicode字符序列,例如,串"Java\u2122"由5個Unicode字符J、a、v、a和TM 。Java沒有內置的字符串類型,而是在標準Java類庫中提供了一個預定義類,很自然的叫做String。每個雙引號“”括起來的字符串都是String類的一個實例:

String e = "";   //an empty string
String greeting = "Hello";

那麼這三者的區別是什麼?

1、可變性

查看源碼簡單來說,String類中使用final關鍵字修飾的字符數組保存字符串,所以String對象是不可變的:
String.java

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
    private final char value[];
    private int hash;
    ...
}

而StringBuilder和StringBuffer都繼承自AbstractStringBuilder,在AbstractStringBuilder類中也是使用字符數組來保存字符串的,但是沒有用final關鍵字修飾:
AbstractStringBuilder.java

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    char[] value;
    int count;
    AbstractStringBuilder(){
    }
    AbstractStringBuilder(int capacity){
        valeu = new char[capacity];
    }
    ...
}

StringBuilder.java

public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence{
    public StringBuilder() {
        super(16);
    }
    ...
}

StringBuffer.java

public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence{
    private transient char[] toStringCache;
    public StringBuffer() {
        super(16);
    }
    ...
}

從而也可以看出三個類也是用final修飾的,所以是不可繼承的。

2、線程安全性

String中的對象是不可變的,也可以理解爲常量,線程安全。AbstractStringBuilder是StringBuilder和StringBuffer的父類,定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。而StringBuilder並沒有對方法加同步鎖,所以是線程不安全的。

3、性能

每次對String進行改變的時候,都會生成一個新的String對象,然後將引用指向新的String對象。StringBuffer和StringBuilder每次都是對對象本身進行操作,而不生成新的對象也不改變引用的指向。相同情況下使用StringBuilder相比使用StringBuffer僅能獲得10%-15%左右的性能提升,卻要冒線程不安全的風險。

4、使用建議

  1. 操作少量數據 String
  2. 單線程,字符串緩衝區下操作大量數據 StringBuilder
  3. 多線程,字符串緩衝區下操作大量數據 StringBuffer

5、常用API

  • java.lang.String
//返回給定位置的代碼單元。
char charAt(int index)

//按照字典順序,如果字符串位於other之前,返回一個負數;如果字符串在other之後,返回一個正數;如果兩個字符串相等,返回0.
int compareTo(String other)

//用數組中offset開始的count個碼點構成一個字符串
new String(int[] codePoints, int offset, int count) 

//如果字符串與other相等,返回true,反之返回false
boolean equals(Object other)

//如果字符串與other相等(忽略大小寫),返回true,反之返回false
boolean equalsIgnoreCase(String other) 

//如果字符串以prefix開頭,返回true
boolean startsWith(String prefix) 

//如果字符串以suffix結尾,返回true
boolean endsWith(String suffix)

//返回字符串str或代碼點cp匹配的第一個子串開始的位置。這個位置從索引0或者fromIndex開始計算。
//如果在原始串中不存在str,返回-1
int indexOf(String str)
int indexOf(String str, int fromIndex) 
int indexOf(int cp) 
int indexOf(int cp, int fromIndex) 

//返回字符串str或代碼點cp匹配的最後一個子串開始的位置。這個位置從原始串結尾端或fromIndex開始計算
int lastIndexOf(String str)
int lastIndexOf(String str, int fromIndex) 
int lastIndexOf(int cp) 
int lastIndexOf(int cp, int fromIndex) 

//返回字符串的長度
int length() 

//返回一個新字符串。這個字符串用newString代替原始字符串中所有oldString。
//可以用String或StringBuffer或StringBuilder對象作爲CharSequence參數。
String replace(CharSequence oldString, CharSequence newString) 

//返回一個新字符串。這個字符串包含原始字符串中從beginIndex到串尾的所有代碼單元
String substring(int beginIndex)

//返回一個新字符串。這個字符串包含原始字符串中從beginIndex到endindex-1的所有代碼單元
String substring(int beginIndex, int endIndex)

//返回一個新字符串。這個字符串將原始字符串中的大寫改爲小寫
String toLowerCase()

//返回一個新字符串。這個字符串將原始字符串中的小寫改爲大寫
String toUpperCase()

//返回一個新字符串。這個字符串將刪除原始字符串頭部和尾部的空格
String trim()

//返回一個新字符串。用給定的定界符連接所有元素
String join(CharSequence delimiter, CharSequence... elements)
  • java.lang.StringBulider
//構造一個空字符串構建器
StringBuilder()

//返回構建器或緩衝器中的代碼單元數量
int length()

//追加一個字符串並返回this
StringBuilder append(char c)

//將第i個代碼單元設置爲c
void setCharAt(int i, chanr c)

//在offset位置插入一個字符串並返回this
StringBuilder insert(int offset, String str)

//刪除偏移量從startIndex到endIndex-1的代碼單元並返回this
StringBuilder delete(int startIdnex, int endIndex)

//返回一個與構建器或緩衝器內容相同的字符串
String toString()
  • java.lang.StringBuffer
    與StringBuilder基本相同
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章