JAVA深化篇_04——字符串相關類StringBuilder和StringBuffer
字符串相關類

String類代表不可變的字符序列
StringBuilder類和StringBuffer類代表可變字符序列。
這三個類的用法,在筆試面試以及實際開發中經常用到,必須掌握好。
String類源碼分析
String 類對象代表不可變的Unicode字符序列,因此我們可以將String對象稱為“不可變對象”。 那什么叫做“不可變對象”呢?指的是對象內部的成員變量的值無法再改變。我們打開String類的源碼,如圖所示:
我們發現字符串內容全部存儲到value[ ]數組中,而變量value是final類型的,也就是常量(即只能被賦值一次)。 這就是“不可變對象”的典型定義方式。
我們發現在前面學習String的某些方法,比如:substring()是對字符串的截取操作,但本質是讀取原字符串內容生成了新的字符串。測試代碼如下:
【示例】String類的簡單使用
public class TestString1 {
public static void main(String[ ] args) {
String s1 = new String("abcdef");
String s2 = s1.substring(2, 4);
// 打?。篴b199863
System.out.println(Integer.toHexString(s1.hashCode()));
// 打?。篶61, 顯然s1和s2不是同一個對象
System.out.println(Integer.toHexString(s2.hashCode()));
}
}
?
在遇到字符串常量之間的拼接時,編譯器會做出優化,即在編譯期間就會完成字符串的拼接。因此,在使用==進行String對象之間的比較時,我們要特別注意,如示例所示。
【示例】字符串常量拼接時的優化
public class TestString2 {
public static void main(String[ ] args) {
//編譯器做了優化,直接在編譯的時候將字符串進行拼接
String str1 = "hello" + " java";//相當于str1 = "hello java";
String str2 = "hellojava";
System.out.println(str1 == str2);//true
String str3 = "hello";
String str4 = " java";
//編譯的時候不知道變量中存儲的是什么,所以沒辦法在編譯的時候優化
String str5 = str3 + str4;
System.out.println(str2 == str5);//false
}
}
StringBuffer和StringBuilder可變字符序列
StringBuffer和StringBuilder都是可變的字符序列。
-
StringBuffer 線程安全,做線程同步檢查, 效率較低。
-
StringBuilder 線程不安全,不做線程同步檢查,因此效率較高。建議采用該類。
· 常用方法列表:
-
重載的
public StringBuilder append(…)方法可以為該
StringBuilder對象添加字符序列,仍然返回自身對象。 -
方法
public StringBuilder delete(int start,int end)可以刪除從
start開始到end-1為止的一段字符序列,仍然返回自身對象。 -
方法
public StringBuilder deleteCharAt(int index)移除此序列指定位置上的
char,仍然返回自身對象。 -
重載的
public StringBuilder insert(…)方法可以為該StringBuilder 對象在指定位置插入字符序列,仍然返回自身對象。
-
方法
public StringBuilder reverse()用于將字符序列逆序,仍然返回自身對象。
-
方法
public String toString()返回此序列中數據的字符串表示形式。 -
和 String 類含義類似的方法:
public int indexOf(String str)
public int indexOf(String str,int fromIndex)
public String substring(int start)
public String substring(int start,int end)
public int length()
char charAt(int index)
?【示例】StringBuffer/StringBuilder基本用法
public class TestString {
public static void main(String[] args) {
//字符串的拼接
String s = "hello"+"world";
String s2 = "helloworld";
System.out.println(s==s2);
//StringBuilder用法 線程不同步 線程不安全 但效率高
StringBuilder s1 = new StringBuilder("中國人");
//append 用法 添加
System.out.println(s1.append("愛").append("中國"));
//insert 用法 插入
System.out.println(s1.insert(0,"今天的"));
//StringBuffer用法 線程同步 線程安全 效率低
StringBuffer b2 = new StringBuffer("中國");
//insert 方法 返回自身 連續插入
System.out.println(b2.insert(0,"好").insert(0,"常").insert(0,"非"));
//delete 方法 刪除下標在[x,y)的字符
b2.delete(0,3);
System.out.println(b2);
//deletecharAt() 刪除某個字符
b2.deleteCharAt(1);
System.out.println(b2);
System.out.println(s1.delete(0,3));
//reverse 方法 字符串逆序
System.out.println(s1.reverse());
}
}
?
執行結果如圖所示:

StringBuffer和StringBuilder都是可變的字符序列。
-
StringBuffer 線程安全,做線程同步檢查, 效率較低。
-
StringBuilder 線程不安全,不做線程同步檢查,因此效率較高。建議采用該類。
不可變和可變字符序列使用陷阱

· String使用的陷阱
String一經初始化后,就不會再改變其內容了。對String字符串的操作實際上是對其副本(原始拷貝)的操作,原來的字符串一點都沒有改變。比如:
String s ="a"; 創建了一個字符串
s = s+"b"; 實際上原來的a字符串對象已經丟棄了,現在又產生了另一個字符串s+"b"(也就是ab)。 如果多次執行這些改變串內容的操作,會導致大量副本字符串對象存留在內存中,降低效率。如果這樣的操作放到循環中,會極大影響程序的時間和空間性能,甚至會造成服務器的崩潰。
相反,StringBuilder和StringBuffer類是對原字符串本身操作的,可以對字符串進行修改而不產生副本拷貝或者產生少量的副本。因此可以在循環中使用。
【示例】String和StringBuilder在字符串頻繁修改時的效率測試
public class TestString2 {
public static void main(String[] args) {
/*使用String進行字符串的拼接*/
String s1="";
long num1=Runtime.getRuntime().freeMemory();//獲取系統剩余內存空間
long time1= System.currentTimeMillis();//獲取系統的當前時間
for (int i=0;i<5000;i++){
s1=s1+i; //會產生5000個對象
}
long num2 = Runtime.getRuntime().freeMemory();
long time2 = System.currentTimeMillis();
System.out.println("系統消耗的空間:"+(num1-num2));
System.out.println("系統消耗的時間:"+(time2-time1));
/*使用StringBuildier進行添加字符*/
StringBuilder s2=new StringBuilder("");
long num3=Runtime.getRuntime().freeMemory();//獲取系統剩余內存空間
long time3= System.currentTimeMillis();//獲取系統的當前時間
for(int i=0;i<5000;i++){
s2.append(i); //只有這一個對象
}
long num4 = Runtime.getRuntime().freeMemory();
long time4 = System.currentTimeMillis();
System.out.println("系統消耗的空間:"+(num3-num4));
System.out.println("系統消耗的時間:"+(time4-time3));
}
}
執行結果如圖所示:

浙公網安備 33010602011771號