java中String、StringBuffer、StringBuilder的總結

看了很多關於java的string的相關知識,這裏做一個較爲全面的總結,內容轉自不同地方的博客,鑑於出處較多,就不一一列舉了。

java中String、StringBuffer、StringBuilder是編程中經常使用的字符串類,他們之間的區別也是經常在面試中會問到的問題。現在總結一下,看看他們的不同與相同。

String 字符串常量
StringBuffer 字符串變量(線程安全)
StringBuilder 字符串變量(非線程安全)

1.可變與不可變

  String類中使用字符數組保存字符串,如下就是,因爲有“final”修飾符,所以可以知道string對象是不可變的。

    private final char value[];

  StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串,如下就是,可知這兩種對象都是可變的。

    char[] value;

2.是否多線程安全

  String中的對象是不可變的,也就可以理解爲常量,顯然線程安全。

  AbstractStringBuilder是StringBuilder與StringBuffer的公共父類,定義了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。

  StringBuffer對方法加了同步鎖或者對調用的方法加了同步鎖,所以是線程安全的。看如下源碼:
  

public synchronized StringBuffer reverse() {
    super.reverse();
    return this;
}

public int indexOf(String str) {
    return indexOf(str, 0); //存在 public synchronized int indexOf(String str, int fromIndex) 方法
}

StringBuilder並沒有對方法進行加同步鎖,所以是非線程安全的。

3.StringBuilder與StringBuffer共同點

  StringBuilder與StringBuffer有公共父類AbstractStringBuilder(抽象類)。

  抽象類與接口的其中一個區別是:抽象類中可以定義一些子類的公共方法,子類只需要增加新的功能,不需要重複寫已經存在的方法;而接口中只是對方法的申明和常量的定義。

  StringBuilder、StringBuffer的方法都會調用AbstractStringBuilder中的公共方法,如super.append(…)。只是StringBuffer會在方法上加synchronized關鍵字,進行同步。

  最後,如果程序不是多線程的,那麼使用StringBuilder效率高於StringBuffer。

4、String的常用方法

4.1、String對象的初始化

由於String對象特別常用,所以在對String對象進行初始化時,Java提供了一種簡化的特殊語法,格式如下:

                                  String s = “abc”;                         
                                   s = “Java語言”;

其實按照面向對象的標準語法,其格式應該爲:

                        String s = new String(“abc”);
                        s = new String(“Java語言”);

只是按照面向對象的標準語法,在內存使用上存在比較大的浪費。例如String s = new String(“abc”);實際上創建了兩個String對象,一個是”abc”對象,存儲在常量空間中,一個是使用new關鍵字爲對象s申請的空間。

4.2 獲取指定索引的字符值

charAt方法的作用是按照索引值(規定字符串中第一個字符的索引值是0,第二個字符的索引值是1,依次類推),獲得字符串中的指定字符。例如:

                                 String s = “abc”;
                                 char c = s.chatAt(1);

則變量c的值是’b’。

4.3 比較兩個字符串的大小

compareTo方法比較兩個字符串的大小,比較的原理是依次比較每個字符的字符編碼。首先比較兩個字符串的第一個字符,如果第一個字符串的字符編碼大於第二個的字符串的字符編碼,則返回大於0的值,如果小於則返回小於0的值,如果相等則比較後續的字符,如果兩個字符串中的字符編碼完全相同則返回0。例如:
String s = “abc”;

                                 String s1 = “abd”;
                                 int value = s.compareTo(s1);

則value的值是小於0的值,即-1。
在String類中還存在一個類似的方法compareToIgnoreCase,這個方法是忽略字符的大小寫進行比較,比較的規則和compareTo一樣。例如:

                                 String s = “aBc”;
                                 String s1 = “ABC”;
                                 int value = s. compareToIgnoreCase (s1);

則value的值是0,即兩個字符串相等。

4.4、字符串的連接
concat方法將兩個字符串連接以後形成一個新的字符串。例如:

                                 String s = “abc”;
                                 String s1 = “def”;
                                 String s2 = s.concat(s1);

則連接以後生成的新字符串s2的值是”abcdef”,而字符串s和s1的值不發生改變。如果需要連接多個字符串,可以使用如下方法:

                                 String s = “abc”;
                                 String s1 = “def”;
                                 String s2 = “1234”;
                                 String s3 = s.concat(s1).concat(s2);

則生成的新字符串s3的值爲”abcdef1234”。
其實在實際使用時,語法上提供了一種更簡單的形式,就是使用“+”進行字符串的連接。例如:

                                 String s = “abc” + “1234”;

則字符串s的值是”abc1234”,這樣書寫更加簡單直觀。而且使用“+”進行連接,不僅可以連接字符串,也可以連接其他類型。但是要求進行連接時至少有一個參與連接的內容是字符串類型。而且“+”匹配的順序是從左向右,如果兩邊連接的內容都是基本數字類型則按照加法運算,如果參與連接的內容有一個是字符串才按照字符串進行連接。
例如:

                                 int a = 10;
                                 String s = “123” + a + 5;

則連接以後字符串s的值是“123105”,計算的過程爲首先連接字符串”123”和變量a的值,生成字符串”12310”,然後使用該字符串再和數字5進行連接生成最終的結果。
而如下代碼:

                                 int a = 10;
                                 String s = a + 5 + “123”;

則連接以後字符串s的值是”15123”,計算的過程爲首先計算a和數字5,由於都是數字型則進行加法運算或者數字值15,然後再使用數字值15和字符串”123”進行連接獲得最終的結果。
而下面的連接代碼是錯誤的:

                                 int a = 12;
                                 String s = a + 5 + ‘s’;

因爲參與連接的沒有一個字符串,則計算出來的結果是數字值,在賦值時無法將一個數字值賦值給字符串s。

4.5、判斷兩個字符串對象的內容是否相同

equals方法判斷兩個字符串對象的內容是否相同。如果相同則返回true,否則返回false。例如:

                                 String s = “abc”;
                                 String s1 = new String(“abc”);
                                 boolean b = s.equals(s1);

而使用“==”比較的是兩個對象在內存中存儲的地址是否一樣。例如上面的代碼中,如果判斷:

                                  boolean b = (s == s1);

則變量b的值是false,因爲s對象對應的地址是”abc”的地址,而s1使用new關鍵字申請新的內存,所以內存地址和s的”abc”的地址不一樣,所以獲得的值是false。
在String類中存在一個類似的方法equalsIgnoreCase,該方法的作用是忽略大小寫比較兩個字符串的內容是否相同。例如:

                                 String s = “abc”;
                                 String s1 =”ABC”;
                                 boolean b = s. equalsIgnoreCase (s1);

則變量b的值是true。

4.6、查找特定字符或字符串在當前字符串中的起始位置

indexOf方法作用是查找特定字符或字符串在當前字符串中的起始位置,如果不存在則返回-1。例如:

                                 String s = “abcded”;
                                 int index = s.indexOf(‘d’);
                                 int index1 = s.indexOf(‘h’);

則返回字符d在字符串s中第一次出現的位置,數值爲3。由於字符h在字符串s中不存在,則index1的值是-1。當然,也可以從特定位置以後查找對應的字符,例如:

                                 int index = s.indexOf(‘d’,4);

則查找字符串s中從索引值4(包括4)以後的字符中第一個出現的字符d,則index的值是5。
由於indexOf是重載的,也可以查找特定字符串在當前字符串中出現的起始位置,使用方式和查找字符的方式一樣。
另外一個類似的方法是lastIndexOf方法,其作用是從字符串的末尾開始向前查找第一次出現的規定的字符或字符串,例如:

                                 String s = “abcded”;
                                 int index = s. lastIndexOf(‘d’);

則index的值是5。

4.7、返回字符串的長度
length方法
該方法的作用是返回字符串的長度,也就是返回字符串中字符的個數。中文字符也是一個字符。例如:

                             String s = “abc”;
                             String s1 = “Java語言”;
                             int len = s.length();
                             int len1 = s1.length();

則變量len的值是3,變量len1的值是6。

4.8、替換字符串中所有指定的字符

replace方法作用是替換字符串中所有指定的字符,然後生成一個新的字符串。經過該方法調用以後,原來的字符串不發生改變。例如:

                         String s = “abcat”;
                         String s1 = s.replace(‘a’,’1’);

該代碼的作用是將字符串s中所有的字符a替換成字符1,生成的新字符串s1的值是”1bc1t”,而字符串s的內容不發生改變。
如果需要將字符串中某個指定的字符串替換爲其它字符串,則可以使用replaceAll方法,例如:

                         String s = “abatbac”;
                         String s1 = s.replaceAll(“ba”,”12”);

該代碼的作用是將字符串s中所有的字符串”ab”替換爲”12”,生成新的字符串”a12t12c”,而字符串s的內容也不發生改變。
如果只需要替換第一個出現的指定字符串時,可以使用replaceFirst方法,例如:

                         String s = “abatbac”;
                         String s1 = s. replaceFirst (“ba”,”12”);

該代碼的作用是隻將字符串s中第一次出現的字符串”ab”替換爲字符串”12”,則字符串s1的值是”a12tbac”,字符串s的內容也不發生改變。

4.9 字符串的分割
split方法作用是以特定的字符串作爲間隔,拆分當前字符串的內容,一般拆分以後會獲得一個字符串數組。例如:

                         String s = “ab,12,df”;
                         String s1[] = s.split(“,”);

該代碼的作用是以字符串”,”作爲間隔,拆分字符串s,從而得到拆分以後的字符串數字s1,其內容爲:{“ab”,”12”,”df”}。
該方法是解析字符串的基礎方法。
如果字符串中在內部存在和間隔字符串相同的內容時將拆除空字符串,尾部的空字符串會被忽略掉。例如:

                             String s = “abbcbtbb”;
                             String s1[] = s.split(“b”);

則拆分出的結果字符串數組s1的內容爲:{“a”,””,”c”,”t”}。拆分出的中間的空字符串的數量等於中間間隔字符串的數量減一個。例如:

                             String s = “abbbcbtbbb”;
                             String s1[] = s.split(“b”);

則拆分出的結果是:{“a”,””,””,”c”,”t”}。最後的空字符串不論有多少個,都會被忽略。
如果需要限定拆分以後的字符串數量,則可以使用另外一個split方法,例如:

                             String s = “abcbtb1”;
                             String s1[] = s.split(“b”,2);

該代碼的作用是將字符串s最多拆分成包含2個字符串數組。則結果爲:{“a”,”cbtb1”}。如果第二個參數爲負數,則拆分出儘可能多的字符串,包括尾部的空字符串也將被保留。

4.10、取字符串中的子串
substring方法作用是取字符串中的“子串”,所謂“子串”即字符串中的一部分。例如“23”是字符串“123”的子串。
字符串“123”的子串一共有6個:”1”、”2”、”3”、”12”、”23”、”123”。而”32”不是字符串”123”的子串。
例如:

                             String s = “Test”;
                             String s1 = s.substring(2);

則該代碼的作用是取字符串s中索引值爲2(包括)以後的所有字符作爲子串,則字符串s1的值是”st”。
如果數字的值和字符串的長度相同,則返回空字符串。例如:

                             String s = “Test”;
                             String s1 = s.substring(4);

則字符串s1的值是””。
如果需要取字符串內部的一部分,則可以使用帶2個參數的substring方法,例如:

                             String s = “TestString”;
                             String s1 = s.substring(2,5);

則該代碼的作用是取字符串s中從索引值2(包括)開始,到索引值5(不包括)的部分作爲子串,則字符串s1的值是”stS”。
下面是一個簡單的應用代碼,該代碼的作用是輸出任意一個字符串的所有子串。代碼如下:

public static void main(String[] args) {
        String s = "子串示例";
        int len = s.length();
        for (int begin = 0; begin < len - 1; begin++) {
            for (int end = begin + 1; end <= len; end++) {
                System.out.println(s.substring(begin, end));
            }
        }
    }

在該代碼中,循環變量begin代表需要獲得的子串的起始索引值,其變化的區間從第一個字符的索引值0到倒數第二個字符串的索引值len -2,而end代表需要獲得的子串的結束索引值,其變化的區間從起始索引值的後續一個到字符串長度。通過循環的嵌套,可以遍歷字符串中的所有子串。

4.11、字符串轉換爲對應的char數組
toCharArray方法作用和getBytes方法類似,即將字符串轉換爲對應的char數組。例如:

                             String s = “abc”;
                             char[] c = s.toCharArray();

則字符數組c的值爲:{‘a’,’b’,’c’}。

4.12、大小寫轉換
toLowerCase方法的作用是將字符串中所有大寫字符都轉換爲小寫。例如:

                                 String s = “AbC123”;
                                 String s1 = s.toLowerCase();

則字符串s1的值是”abc123”,而字符串s的值不變。
類似的方法是toUpperCase,該方法的作用是將字符串中的小寫字符轉換爲對應的大寫字符。例如:

                                 String s = “AbC123”;
                                 String s1 = s. toUpperCase ();

則字符串s1的值是”ABC123”,而字符串s的值也不變

4.13、將其它類型的數據轉換爲字符串類型
valueOf方法的作用是將其它類型的數據轉換爲字符串類型。需要注意的是,基本數據和字符串對象之間不能使用以前的強制類型轉換的語法進行轉換。
另外,由於該方法是static方法,所以不用創建String類型的對象即可。例如:

                                 int n = 10;
                                 String s = String.valueOf(n);

則字符串s的值是”10”。雖然對於程序員來說,沒有發生什麼變化,但是對於程序來說,數據的類型卻發生了變化。
介紹一個簡單的應用,判斷一個自然數是幾位數字的邏輯代碼如下:

                                 int n = 12345;
                                 String s = String.valueOf(n);
                                 int len = s.length();

則這裏字符串的長度len,就代表該自然數的位數。這種判斷比數學判斷方法在邏輯上要簡單一些。

5、StringBuffer 和StringBuilder的常用方法

一般情況下StringBuilder用的比較多,這裏就簡單的介紹StringBuilder的常用方法,二者大體相同。

5.1、StringBuilder的初始化

                            StringBuilder sb=new StringBuilder();

5.2、添加元素數據
有2種方法可以向StringBuilder 中添加元素,一種是在尾部添加,append(),例如:

                                sb.append("sss");
                                sb.append(4);
                                sb.append('3');

另一種是在指定位置插入指定的元素,例如:

                                sb.insert(0, "2");

5.3、刪除元素
sb.delete(start, end);可以刪除從開始到位置到結束位置的元素,從0開始,結束位置也會被刪除。需要注意的是start和end不能相等,比如說sb.delete(0, 0);是錯誤的,如果要刪除指定位置的字符,可以使用sb.deleteCharAt(index);同樣index從0開始。

5.4、替換元素
可以使用sb.replace(start, end, str)替換掉從開始到結束的元素,替換內容爲str,注意的是str必須是字符串,而且start,和end是可以相等的,這樣就是替換的字符。例如:

                        sb.replace(0, 0, "eu");

類似的還有將某個字符替換成新的字符

                        sb.setCharAt(index, char);

5.5、 字符串反轉
reverse()可以把字符串進行反轉。使用方法爲sb.reverse();

5.6、求字符串的長度
length()方法可以求得字符串的長度,使用方法爲sb.length();

5.7 獲取某個位置的字符和字符出現的位置
char charAt(int index); 獲取某個位置的字符。
int indexOf(String str); 獲取某個字符串在數據中第一次出現的位置

5.8 獲取子串
sb.substring(start, end);獲取從開始到結束位置的子串,返回的還是String類型,如果只寫start則會把從開始位置的以後的字符串全部返回。例如:sb.substring(start)。
如果要返回序列則可以使用 CharSequence out=sb.subSequence(0, 2);

5.9 轉換成字符串
sb.toString()可以轉換成字符串。

發佈了161 篇原創文章 · 獲贊 91 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章