String、StringBuffer和StringBuilder的區(qū)別

類繼承關(guān)系中圖

類繼承關(guān)系圖

特點(diǎn)

String

來(lái)看幾個(gè)例子

String s1 = "hello world";
String s2 = "hello world";
System.out.println(s1 == s2);

輸出結(jié)果是true

String s1 = new String("hello world");
String s2 = new String("hello world");
String s3 = "hello world";
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));

輸出結(jié)果是 false、true、true

在 Java 編譯好的 class 文件中,有個(gè)區(qū)域被稱為常量池(Constant Pool),存儲(chǔ)著各種常量,其中存儲(chǔ)字符串常量的區(qū)域被習(xí)慣地稱為字符串池(String Pool)。在第一個(gè)例子中,有兩個(gè)“hello world”常量,但是在常量池中,只會(huì)創(chuàng)建一個(gè)常量,也就是說(shuō),在編譯好的 class 文件中,只能找到一個(gè)“hello world”常量。因此 s1 和 s2 指向的在常量池中同一個(gè)字符串對(duì)象,“==”比較是否是同一個(gè)對(duì)象,所以結(jié)果返回 true。

擴(kuò)展知識(shí)

private final char value[];

字符串是用一個(gè)不可變的字符數(shù)組來(lái)存儲(chǔ)字符串內(nèi)容,當(dāng) String 對(duì)象創(chuàng)建之后,就不能修改對(duì)象中存儲(chǔ)的內(nèi)容,所以說(shuō),String 類型是不可變的(immutable)
例如

String s1 = new String("hello");
s1 = s1 + " world";

因?yàn)?String 是不可變的,這段代碼會(huì)根據(jù)s1的內(nèi)容和字符串常量“ world”在heap區(qū)創(chuàng)建一個(gè)新的字符串

String s1 = new String("hello world");

該語(yǔ)句創(chuàng)建兩個(gè) String 對(duì)象,一個(gè)是在編譯時(shí),創(chuàng)建于字符串常量區(qū),一個(gè)是在運(yùn)行時(shí),創(chuàng)建于heap區(qū)。

Java對(duì)String進(jìn)行了“+”操作符重載,利用“+”可以將字符串連接。但是需要注意的是

String s1 = "hello" + " world";

該代碼與第一點(diǎn)的例子不一樣,編譯時(shí)編譯器會(huì)直接提取兩個(gè)常量的內(nèi)容,只生成“hello world”一個(gè)字符串,同理,無(wú)論多少個(gè)常量相加,都是生成一個(gè)對(duì)象。

運(yùn)行時(shí)調(diào)用 String 的 intern() 方法可以向 String Pool 中動(dòng)態(tài)添加對(duì)象。

5.String創(chuàng)建的幾種方法

  1. 使用“”。
  2. 使用 new String();
  3. 使用 new String("hello world");
  4. 使用重載操作符“+”

StringBuffer&StringBuilder

StringBuilder一個(gè)可變的字符序列是5.0新增的。此類提供一個(gè)與 StringBuffer 兼容的 API,但不保證同步。該類被設(shè)計(jì)用作 StringBuffer 的一個(gè)簡(jiǎn)易替換,用在字符串緩沖區(qū)被單個(gè)線程使用的時(shí)候(這種情況很普遍)。如果可能,建議優(yōu)先采用該類,因?yàn)樵诖蠖鄶?shù)實(shí)現(xiàn)中,它比 StringBuffer 要快。
Stringbuffer 和 StringBuilder除了線程安全的區(qū)別外,其他基本一致,都繼承于AbstractStringBuffer。
來(lái)看一下AbstractStringBuffer的源碼

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;

    /**
     * This no-arg constructor is necessary for serialization of subclasses.
     */
    AbstractStringBuilder() {
    }

    /**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

    /**
     * Returns the length (character count).
     *
     * @return  the length of the sequence of characters currently
     *          represented by this object
     */
    @Override
    public int length() {
        return count;
    }

    /**
     * Returns the current capacity. The capacity is the amount of storage
     * available for newly inserted characters, beyond which an allocation
     * will occur.
     *
     * @return  the current capacity
     */
    public int capacity() {
        return value.length;
    }

AbstractStringBuffer 使用的是可變的char數(shù)組,在創(chuàng)建 StringBuffer 和 StringBuilder 時(shí)有幾種方式,其中無(wú)參的構(gòu)造方法調(diào)用的是父類的構(gòu)造方法,創(chuàng)建大小為16的char數(shù)組

public StringBuffer() {
    super(16);
}

public StringBuilder() {
    super(16);
}

其他的構(gòu)造方法,StringBuilder 與之類似

public StringBuffer(int capacity) {
    super(capacity);
}

public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
}

public StringBuffer(CharSequence seq) {
    this(seq.length() + 16);
    append(seq);
}

其他常見(jiàn)方法:append、insert


三者區(qū)別

可變性

String 不可變,StringBuffer、StringBuilder可變

速度

StringBuilder > StringBuffer > String

線程安全

String、StringBuilder不安全,StringBuffer安全


總結(jié)

  1. 在編譯階段就能夠確定的字符串常量,完全沒(méi)有必要?jiǎng)?chuàng)建String或StringBuffer對(duì)象。直接使用字符串常量的"+"連接操作效率最高。
  2. StringBuffer對(duì)象的append效率要高于String對(duì)象的"+"連接操作。
  3. 不停的創(chuàng)建對(duì)象是程序低效的一個(gè)重要原因。那么相同的字符串值能否在堆中只創(chuàng)建一個(gè)String對(duì)象那。顯然拘留字符串能夠做到這一點(diǎn),除了程序中的字符串常量會(huì)被JVM自動(dòng)創(chuàng)建拘留字符串之外,調(diào)用String的intern()方法也能做到這一點(diǎn)。當(dāng)調(diào)用intern()時(shí),如果常量池中已經(jīng)有了當(dāng)前String的值,那么返回這個(gè)常量指向拘留對(duì)象的地址。如果沒(méi)有,則將String值加入常量池中,并創(chuàng)建一個(gè)新的拘留字符串對(duì)象。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容