JavaSE知識(shí)點(diǎn)11java深探String、StringBuilder以及StringBuffer

你了解String類(lèi)嗎?

  • 1 想要了解一個(gè)類(lèi),最好的辦法就是看這個(gè)類(lèi)的實(shí)現(xiàn)源代碼
    String類(lèi)的定義如下:
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence
{
    private final char value[];
    private final int offset;
    private final int count;
    private int hash;
    private static final long serialVersionUID = -6849794470754667710L;
    ....
}
  • 1 String類(lèi)是final類(lèi),也即意味著String類(lèi)不能被繼承,并且它的屬性和方法都默認(rèn)為final方法。
  • 2 String類(lèi)其實(shí)是通過(guò)char數(shù)組來(lái)保存字符串的。
  • 3 下面再繼續(xù)看String類(lèi)的一些方法實(shí)現(xiàn)
public String substring(int beginIndex, int endIndex) {
    if (beginIndex < 0) {
        throw new StringIndexOutOfBoundsException(beginIndex);
    }
    if (endIndex > count) {
        throw new StringIndexOutOfBoundsException(endIndex);
    }
    if (beginIndex > endIndex) {
        throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
    }
    return ((beginIndex == 0) && (endIndex == count)) ? this :
        new String(offset + beginIndex, endIndex - beginIndex, value);
    }
 
 public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    char buf[] = new char[count + otherLen];
    getChars(0, count, buf, 0);
    str.getChars(0, otherLen, buf, count);
    return new String(0, count + otherLen, buf);
    }
 
 public String replace(char oldChar, char newChar) {
    if (oldChar != newChar) {
        int len = count;
        int i = -1;
        char[] val = value; /* avoid getfield opcode */
        int off = offset;   /* avoid getfield opcode */
 
        while (++i < len) {
        if (val[off + i] == oldChar) {
            break;
        }
        }
        if (i < len) {
        char buf[] = new char[len];
        for (int j = 0 ; j < i ; j++) {
            buf[j] = val[off+j];
        }
        while (i < len) {
            char c = val[off + i];
            buf[i] = (c == oldChar) ? newChar : c;
            i++;
        }
        return new String(0, len, buf);
        }
    }
    return this;

從上面的三個(gè)方法可以看出,無(wú)論是substring、concat還是replace操作都不是在原有的字符串上進(jìn)行的,而是重新生成了一個(gè)新的字符串對(duì)象。也就是說(shuō)進(jìn)行這些操作后,最原始的字符串并沒(méi)有被改變。

  • 5 對(duì)String對(duì)象的任何改變都不影響到原對(duì)象,相關(guān)的任何change操作都會(huì)生成新的對(duì)象。

深入理解String、StringBuffer、StringBuilder

  • 1 String str="hello world"和String str=new String("hello world")的區(qū)別
public class MyTest{
    public static void main(String[] args) {
        String str1 = "hello world";
        String str2 = new String("hello world");
        String str3 = "hello world";
        String str4 = new String("hello world");
         
        System.out.println(str1==str2);
        System.out.println(str1==str3);
        System.out.println(str2==str4);
    }
}

輸出結(jié)果為:

false
true
false

1)在class文件中有一部分 來(lái)存儲(chǔ)編譯期間生成的 字面常量以及符號(hào)引用,這部分叫做class文件常量池,在運(yùn)行期間對(duì)應(yīng)著方法區(qū)的運(yùn)行時(shí)常量池。
2)因此在上述代碼中,String str1 = "hello world";和String str3 = "hello world"; 都在編譯期間生成了 字面常量和符號(hào)引用,運(yùn)行期間字面常量"hello world"被存儲(chǔ)在運(yùn)行時(shí)常量池(當(dāng)然只保存了一份)。通過(guò)這種方式來(lái)將String對(duì)象跟引用綁定的話(huà),JVM執(zhí)行引擎會(huì)先在運(yùn)行時(shí)常量池查找是否存在相同的字面常量,如果存在,則直接將引用指向已經(jīng)存在的字面常量;否則在運(yùn)行時(shí)常量池開(kāi)辟一個(gè)空間來(lái)存儲(chǔ)該字面常量,并將引用指向該字面常量。
3)總所周知,通過(guò)new關(guān)鍵字來(lái)生成對(duì)象是在堆區(qū)進(jìn)行的,而在堆區(qū)進(jìn)行對(duì)象生成的過(guò)程是不會(huì)去檢測(cè)該對(duì)象是否已經(jīng)存在的。因此通過(guò)new來(lái)創(chuàng)建對(duì)象,創(chuàng)建出的一定是不同的對(duì)象,即使字符串的內(nèi)容是相同的。

  • 2 String、StringBuffer以及StringBuilder的區(qū)別
    1)既然在Java中已經(jīng)存在了String類(lèi),那為什么還需要StringBuilder和StringBuffer類(lèi)呢?
    那么看下面這段代碼:
public class MyTest{
    public static void main(String[] args) {
        String string = "";
        for(int i=0;i<10000;i++){
            string += "hello";
        }
    }
}

這句 string += "hello";的過(guò)程相當(dāng)于將原有的string變量指向的對(duì)象內(nèi)容取出與"hello"作字符串相加操作再存進(jìn)另一個(gè)新的String對(duì)象當(dāng)中,再讓string變量指向新生成的對(duì)象。
2)再看下面這段代碼:

public class MyTest {
    public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder();
        for(int i=0;i<10000;i++){
            stringBuilder.append("hello");
        }
    }
}

只生成了一個(gè)對(duì)象,append操作是在原有對(duì)象的基礎(chǔ)上進(jìn)行的。因此在循環(huán)了10000次之后,這段代碼所占的資源要比上面小得多。
3)那么有人會(huì)問(wèn)既然有了StringBuilder類(lèi),為什么還需要StringBuffer類(lèi)?
查看源代碼便一目了然,事實(shí)上,StringBuilder和StringBuffer類(lèi)擁有的成員屬性以及成員方法基本相同,區(qū)別是StringBuffer類(lèi)的成員方法前面多了一個(gè)關(guān)鍵字:synchronized,不用多說(shuō),這個(gè)關(guān)鍵字是在多線(xiàn)程訪問(wèn)時(shí)起到安全保護(hù)作用的,也就是說(shuō)StringBuffer是線(xiàn)程安全的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線(xiàn)程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,692評(píng)論 18 399
  • java中String的常用方法 1、length()字符串的長(zhǎng)度 例:char chars[]={'a','b'...
    赤赤有名閱讀 2,194評(píng)論 0 10
  • final關(guān)鍵字(最終) final修飾的類(lèi)無(wú)法被繼承. final修飾的方法無(wú)法被覆蓋. final修飾的局部變...
    yangliangliang閱讀 731評(píng)論 0 0
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問(wèn)題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,921評(píng)論 0 33
  • 讀徐公子勝治的《神游》。讀到“入妄”“破妄”一卷,心有所感。 創(chuàng)業(yè)如修行。我一直在創(chuàng)業(yè),自然曾經(jīng)入妄。也許現(xiàn)在也在...
    寫(xiě)作喚醒教練一一葉小問(wèn)閱讀 1,061評(píng)論 1 1

友情鏈接更多精彩內(nèi)容