Java常用類06:String 類(下)

StringBuilder 和 StringBuffer

1、概述

【演示:查看源碼及API文檔】

public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
}

StringBuilder 是一個可變的字符序列。它繼承於AbstractStringBuilder,實現了CharSequence接口。 StringBuffer 也是繼承於AbstractStringBuilder的子類;但是,StringBuilder和StringBuffer不同,前者 是非線程安全的,後者是線程安全的。

StringBuilder 和 CharSequence之間的關係圖如下:

在這裏插入圖片描述

【源碼概覽】

package java.lang;
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
static final long serialVersionUID = 4383685877147921099L;
// 構造函數。默認的字符數組大小是16。
public StringBuilder() {
super(16);
}
// 構造函數。指定StringBuilder的字符數組大小是capacity。
public StringBuilder(int capacity) {
super(capacity);
}
// 構造函數。指定字符數組大小=str長度+15,且將str的值賦值到當前字符數組中。
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
// 構造函數。指定字符數組大小=seq長度+15,且將seq的值賦值到當前字符數組中。
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
// 追加“對象obj對應的字符串”。String.valueOf(obj)實際上是調用obj.toString()
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
// 追加“str”。
public StringBuilder append(String str) {
super.append(str);
return this;
}
// 追加“sb的內容”。
private StringBuilder append(StringBuilder sb) {
if (sb == null)
return append("null");
int len = sb.length();
int newcount = count + len;
if (newcount > value.length)
expandCapacity(newcount);
sb.getChars(0, len, value, count);
count = newcount;
return this;
}
// 追加“sb的內容”。
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
// 追加“s的內容”。
public StringBuilder append(CharSequence s) {
if (s == null)
s = "null";
if (s instanceof String)
return this.append((String)s);
if (s instanceof StringBuffer)
return this.append((StringBuffer)s);
if (s instanceof StringBuilder)
return this.append((StringBuilder)s);
return this.append(s, 0, s.length());
}
// 追加“s從start(包括)到end(不包括)的內容”。
public StringBuilder append(CharSequence s, int start, int end) {
super.append(s, start, end);
return this;
}
// 追加“str字符數組對應的字符串”
public StringBuilder append(char[] str) {
super.append(str);
return this;
}
// 追加“str從offset開始的內容,內容長度是len”
public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
}
// 追加“b對應的字符串”
public StringBuilder append(boolean b) {
super.append(b);
return this;
}
// 追加“c”
public StringBuilder append(char c) {
super.append(c);
return this;
}
// 追加“i”
public StringBuilder append(int i) {
super.append(i);
return this;
}
// 追加“lng”
public StringBuilder append(long lng) {
super.append(lng);
return this;
}
// 追加“f”
public StringBuilder append(float f) {
super.append(f);
return this;
}
// 追加“d”
public StringBuilder append(double d) {
super.append(d);
return this;
}
// 追加“codePoint”
public StringBuilder appendCodePoint(int codePoint) {
super.appendCodePoint(codePoint);
return this;
}
// 刪除“從start(包括)到end的內容”
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
}
// 刪除“位置index的內容”
public StringBuilder deleteCharAt(int index) {
super.deleteCharAt(index);
return this;
}
// “用str替換StringBuilder中從start(包括)到end(不包括)的內容”
public StringBuilder replace(int start, int end, String str) {
super.replace(start, end, str);
return this;
}
// “在StringBuilder的位置index處插入‘str中從offset開始的內容’,插入內容長度是
len”
public StringBuilder insert(int index, char[] str, int offset,
int len)
{
super.insert(index, str, offset, len);
return this;
}
// “在StringBuilder的位置offset處插入obj對應的字符串”
public StringBuilder insert(int offset, Object obj) {
return insert(offset, String.valueOf(obj));
}
// “在StringBuilder的位置offset處插入str”
public StringBuilder insert(int offset, String str) {
super.insert(offset, str);
return this;
}
// “在StringBuilder的位置offset處插入str”
public StringBuilder insert(int offset, char[] str) {
super.insert(offset, str);
return this;
}
// “在StringBuilder的位置dstOffset處插入s”
public StringBuilder insert(int dstOffset, CharSequence s) {
if (s == null)
s = "null";
if (s instanceof String)
return this.insert(dstOffset, (String)s);
return this.insert(dstOffset, s, 0, s.length());
}
// “在StringBuilder的位置dstOffset處插入's中從start到end的內容'”
public StringBuilder insert(int dstOffset, CharSequence s,
int start, int end)
{
super.insert(dstOffset, s, start, end);
return this;
}
// “在StringBuilder的位置Offset處插入b”
public StringBuilder insert(int offset, boolean b) {
super.insert(offset, b);
return this;
}
// “在StringBuilder的位置Offset處插入c”
public StringBuilder insert(int offset, char c) {
super.insert(offset, c);
return this;
}
// “在StringBuilder的位置Offset處插入i”
public StringBuilder insert(int offset, int i) {
return insert(offset, String.valueOf(i));
}
// “在StringBuilder的位置Offset處插入l”
public StringBuilder insert(int offset, long l) {
return insert(offset, String.valueOf(l));
}
// “在StringBuilder的位置Offset處插入f”
public StringBuilder insert(int offset, float f) {
return insert(offset, String.valueOf(f));
}
// “在StringBuilder的位置Offset處插入d”
public StringBuilder insert(int offset, double d) {
return insert(offset, String.valueOf(d));
}
// 返回“str”在StringBuilder的位置
public int indexOf(String str) {
return indexOf(str, 0);
}
// 從fromIndex開始查找,返回“str”在StringBuilder的位置
public int indexOf(String str, int fromIndex) {
return String.indexOf(value, 0, count,
str.toCharArray(), 0, str.length(),
fromIndex);
}
// 從後向前查找,返回“str”在StringBuilder的位置
public int lastIndexOf(String str) {
return lastIndexOf(str, count);
}
// 從fromIndex開始,從後向前查找,返回“str”在StringBuilder的位置
public int lastIndexOf(String str, int fromIndex) {
return String.lastIndexOf(value, 0, count,
str.toCharArray(), 0, str.length(),
fromIndex);
}
// 反轉StringBuilder
public StringBuilder reverse() {
super.reverse();
return this;
}
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
    // 序列化對應的寫入函數
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeInt(count);
s.writeObject(value);
}
// 序列化對應的讀取函數
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
count = s.readInt();
value = (char[]) s.readObject();
}
}

2、常用方法

1、insert

package com.string;

import java.util.HashMap;

public class Demo09 {
    public static void main(String[] args) {
        testAppendAPIs();
    }
    /**
     * StringBuilder 的append()示例
     */
    private static void testAppendAPIs() {
        System.out.println("------------------- testAppendAPIs -------------------");
        StringBuilder sbuilder = new StringBuilder();
        // 追加字符數組
        sbuilder.append(new char[]{'a', 'b', 'c', 'd', 'e'});
        // 追加字符數組。0表示字符數組起始位置,3表示長度
        sbuilder.append(new char[]{'A', 'B', 'C', 'D', 'E'}, 0, 3);
        // 追加float
        sbuilder.append(1.414f);
        // 追加double
        sbuilder.append(3.14159d);
        // 追加boolean
        sbuilder.append(true);
        // 追加char
        sbuilder.append('\n');
        // 追加int
        sbuilder.append(100);
        // 追加long
        sbuilder.append(12345L);
        // 追加StringBuilder對象
        sbuilder.append(new StringBuilder("StringBuilder"));
        // 追加StringBuilder對象。6表示被追加對象的起始位置(包括),13是結束位置(不包括)
        sbuilder.append(new StringBuilder("STRINGBUILDER"), 6, 13);
        // 追加StringBuffer對象。
        sbuilder.append(new StringBuffer("StringBuffer"));
        // 追加StringBuffer對象。6表示被追加對象的起始位置(包括),12是結束位置(不包括)
        sbuilder.append(new StringBuffer("STRINGBUFFER"), 6, 12);
        // 追加String對象。
        sbuilder.append("String");
        // 追加String對象。1表示被追加對象的起始位置(包括),6是結束位置(不包括)
        sbuilder.append("0123456789", 1, 6);
        // 在位置0處插入String對象。1表示被在位置0處插入對象的起始位置(包括),6是結束位置(不包括)
        sbuilder.insert(0, "0123456789", 1, 6);
        sbuilder.insert(0, '\n');
        // 在位置0處插入Object對象。此處以HashMap爲例
        HashMap map = new HashMap();
        map.put("1", "one");
        map.put("2", "two");
        map.put("3", "three");
        sbuilder.insert(0, map);
        System.out.printf("%s\n\n", sbuilder);

    }

}

2、append

package com.string;

import java.util.HashMap;

public class Demo10 {
    public static void main(String[] args) {
    }
    private static void testAppendAPIs() {
        System.out.println("------------------- testAppendAPIs ----------------- --");
        StringBuilder sbuilder = new StringBuilder();
        // 追加字符數組
        sbuilder.append(new char[]{'a','b','c','d','e'});
        // 追加字符數組。0表示字符數組起始位置,3表示長度
        sbuilder.append(new char[]{'A','B','C','D','E'}, 0, 3);
        // 追加float
        sbuilder.append(1.414f);
        // 追加double
        sbuilder.append(3.14159d);
        // 追加boolean
        sbuilder.append(true);
        // 追加char
        sbuilder.append('\n');
        // 追加int
        sbuilder.append(100);
        // 追加long
        sbuilder.append(12345L);
        // 追加StringBuilder對象
        sbuilder.append(new StringBuilder("StringBuilder"));
        // 追加StringBuilder對象。6表示被追加對象的起始位置(包括),13是結束位置(不包括)
        sbuilder.append(new StringBuilder("STRINGBUILDER"), 6, 13);
        // 追加StringBuffer對象。
        sbuilder.append(new StringBuffer("StringBuffer"));
        // 追加StringBuffer對象。6表示被追加對象的起始位置(包括),12是結束位置(不包括)
        sbuilder.append(new StringBuffer("STRINGBUFFER"), 6, 12);
        // 追加String對象。
        sbuilder.append("String");
        // 追加String對象。1表示被追加對象的起始位置(包括),6是結束位置(不包括)
        sbuilder.append("0123456789", 1, 6);
        sbuilder.append('\n');
        // 追加Object對象。此處以HashMap爲例
        HashMap map = new HashMap();
        map.put("1", "one");
        map.put("2", "two");
        map.put("3", "three");
        sbuilder.append(map);
        sbuilder.append('\n');
        // 追加unicode編碼
        sbuilder.appendCodePoint(0x5b57); // 0x5b57是“字”的unicode編碼
        sbuilder.appendCodePoint(0x7b26); // 0x7b26是“符”的unicode編碼
        sbuilder.appendCodePoint(0x7f16); // 0x7f16是“編”的unicode編碼
        sbuilder.appendCodePoint(0x7801); // 0x7801是“碼”的unicode編碼
        System.out.printf("%s\n\n", sbuilder);
    }

}

3、replace

package com.string;

public class Demo12 {
    public static void main(String[] args) {
        StringBuilder sb;
        sb = new StringBuilder("0123456789");
        sb.replace(0,3,"ABCDE");
        System.out.printf("sb=%s\n", sb);

        sb = new StringBuilder("0123456789");
        sb.reverse();
        System.out.printf("sb=%s\n",sb);

        sb = new StringBuilder("0123456789");
        sb.setCharAt(0,'M');
        System.out.printf("sb=%s\n",sb);

    }
}

4、delete

package com.string;

public class Demo13 {
    public static void main(String[] args) {
        testDeleteAPIs();
    }
    private static void testDeleteAPIs() {
        System.out.println("------------------- testDeleteAPIs -------------------");
        StringBuilder sbuilder = new StringBuilder("0123456789");
        // 刪除位置0的字符,剩餘字符是“123456789”。
        sbuilder.deleteCharAt(0);
        // 刪除位置3(包括)到位置6(不包括)之間的字符,剩餘字符是“123789”。
        sbuilder.delete(3,6);
        // 獲取sb中從位置1開始的字符串
        String str1 = sbuilder.substring(1);
        // 獲取sb中從位置3(包括)到位置5(不包括)之間的字符串
        String str2 = sbuilder.substring(3, 5);
        // 獲取sb中從位置3(包括)到位置5(不包括)之間的字符串,獲取的對象是CharSequence對象,此處轉型爲String
        String str3 = (String)sbuilder.subSequence(3, 5);
        System.out.printf("sbuilder=%s\nstr1=%s\nstr2=%s\nstr3=%s\n",
                sbuilder, str1, str2, str3);
    }

}

5、index

package com.string;

public class Demo14 {
    public static void main(String[] args) {
        testIndexAPIs();
    }
    private static void testIndexAPIs() {
        System.out.println("-------------------------------- testIndexAPIs ----- ---------------------------");
        StringBuilder sbuilder = new StringBuilder("abcAbcABCabCaBcAbCaBCabc");
        System.out.printf("sbuilder=%s\n", sbuilder);
        // 1. 從前往後,找出"bc"第一次出現的位置
        System.out.printf("%-30s = %d\n", "sbuilder.indexOf(\"bc\")",
                sbuilder.indexOf("bc"));
        // 2. 從位置5開始,從前往後,找出"bc"第一次出現的位置
        System.out.printf("%-30s = %d\n", "sbuilder.indexOf(\"bc\", 5)",
                sbuilder.indexOf("bc", 5));
        // 3. 從後往前,找出"bc"第一次出現的位置
        System.out.printf("%-30s = %d\n", "sbuilder.lastIndexOf(\"bc\")",
                sbuilder.lastIndexOf("bc"));
        // 4. 從位置4開始,從後往前,找出"bc"第一次出現的位置
        System.out.printf("%-30s = %d\n", "sbuilder.lastIndexOf(\"bc\", 4)",
                sbuilder.lastIndexOf("bc", 4));
        System.out.println();
    }
}


6、其他API

package com.string;

public class Demo15 {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("0123456789");
        int cap = sb.capacity();
        System.out.printf("cap=%d\n",cap);
        /*
        capacity()返回的是字符串緩衝區的容量
        StringBuffer( ); 分配16個字符的緩衝區
        StringBuffer( int len ); 分配len個字符的緩衝區
        StringBuffer( String s ); 除了按照s的大小分配空間外,再分配16個 字符的緩衝區
        你的StringBuffer是用字符構造的,"0123456789"的長度是10另外再分配16個字符,所
        以一共是26。
        */

        char c = sb.charAt(6);
        System.out.printf("c=%c\n",c);

        char[] carr = new char[4];
        sb.getChars(3,7,carr,0);
        for (int i = 0; i < carr.length; i++) {
            System.out.printf("carr[%d]=%c",i,carr[i]);

        }
        System.out.println();
    }
}

3、StringBuffer

和StringBulider用法差不多,不過多介紹,主要看一下三者的區別

4、小結

【String、StringBuffer、StringBuilder之間的區別】

首先需要說明的是:

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

在大多數情況下三者在執行速度方面的比較:StringBuilder > StringBuffer > String 解釋: String 類型和 StringBuffer 類型的主要性能區別其實在於 String 是不可變的對象, 因此在每次對 String 類型進行改變的時候其實都等同於生成了一個新的 String 對象,然後將指針指向新的 String 對象,所以 經常改變內容的字符串最好不要用 String ,因爲每次生成對象都會對系統性能產生影響,特別當內存中 無引用對象多了以後, JVM 的 GC 就會開始工作,那速度是一定會相當慢的。

而如果是使用 StringBuffer 類則結果就不一樣了,每次結果都會對 StringBuffer 對象本身進行操作,而 不是生成新的對象,再改變對象引用。所以在一般情況下我們推薦使用 StringBuffer ,特別是字符串對 象經常改變的情況下。

爲什麼是大多數情況呢?

在某些特別情況下, 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”;

大部分情況下StringBuilder的速度要大於StringBuffer:

java.lang.StringBuilder一個可變的字符序列是5.0新增的。(大多數情況下就是我們是在單線程下進行 的操作,所以大多數情況下是建議用StringBuilder而不用StringBuffer的)此類提供一個與 StringBuffer 兼容的 API,但不保證同步。該類被設計用作 StringBuffer 的一個簡易替換,用在字符串緩衝區被單個 線程使用的時候(這種情況很普遍)。如果可能,建議優先採用該類,因爲在大多數實現中,它比 StringBuffer 要快。兩者的方法基本相同。

對於三者使用的總結:

1)如果要操作少量的數據用 = String

2)單線程操作字符串緩衝區 下操作大量數據 = StringBuilder

3)多線程操作字符串緩衝區 下操作大量數據 = StringBuffer

5、面試題的回答

StringBuilder 與StringBuffer的區別,StringBuilder與String的區別。

1)StringBuilder效率高,線程不安全,StringBuffer效率低,線程安全。

2)String是不可變字符串,StringBuilder是可變字符串。爲什麼有這樣的差異,可以深入源碼去解析, 比如String類內的 priver final char value[] 等方法的原因。

3)如果是簡單的聲明一個字符串沒有後續過多的操作,使用String,StringBuilder均可,若後續對字符穿 做頻繁的添加,刪除操作,或者是在循環當中動態的改變字符穿的長度應該用StringBuilder。使用String 會產生多餘的字符串,佔用內存空間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章