字符串在開發中經常使用到,但是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、使用建議
- 操作少量數據 String
- 單線程,字符串緩衝區下操作大量數據 StringBuilder
- 多線程,字符串緩衝區下操作大量數據 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基本相同