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

類繼承關系中圖

類繼承關系圖

特點

String

來看幾個例子

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

輸出結果是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));

輸出結果是 false、true、true

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

擴展知識

private final char value[];

字符串是用一個不可變的字符數組來存儲字符串內容,當 String 對象創(chuàng)建之后,就不能修改對象中存儲的內容,所以說,String 類型是不可變的(immutable)
例如

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

因為 String 是不可變的,這段代碼會根據s1的內容和字符串常量“ world”在heap區(qū)創(chuàng)建一個新的字符串

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

該語句創(chuàng)建兩個 String 對象,一個是在編譯時,創(chuàng)建于字符串常量區(qū),一個是在運行時,創(chuàng)建于heap區(qū)。

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

String s1 = "hello" + " world";

該代碼與第一點的例子不一樣,編譯時編譯器會直接提取兩個常量的內容,只生成“hello world”一個字符串,同理,無論多少個常量相加,都是生成一個對象。

運行時調用 String 的 intern() 方法可以向 String Pool 中動態(tài)添加對象。

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

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

StringBuffer&StringBuilder

StringBuilder一個可變的字符序列是5.0新增的。此類提供一個與 StringBuffer 兼容的 API,但不保證同步。該類被設計用作 StringBuffer 的一個簡易替換,用在字符串緩沖區(qū)被單個線程使用的時候(這種情況很普遍)。如果可能,建議優(yōu)先采用該類,因為在大多數實現中,它比 StringBuffer 要快。
Stringbuffer 和 StringBuilder除了線程安全的區(qū)別外,其他基本一致,都繼承于AbstractStringBuffer。
來看一下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數組,在創(chuàng)建 StringBuffer 和 StringBuilder 時有幾種方式,其中無參的構造方法調用的是父類的構造方法,創(chuàng)建大小為16的char數組

public StringBuffer() {
    super(16);
}

public StringBuilder() {
    super(16);
}

其他的構造方法,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);
}

其他常見方法:append、insert


三者區(qū)別

可變性

String 不可變,StringBuffer、StringBuilder可變

速度

StringBuilder > StringBuffer > String

線程安全

String、StringBuilder不安全,StringBuffer安全


總結

  1. 在編譯階段就能夠確定的字符串常量,完全沒有必要創(chuàng)建String或StringBuffer對象。直接使用字符串常量的"+"連接操作效率最高。
  2. StringBuffer對象的append效率要高于String對象的"+"連接操作。
  3. 不停的創(chuàng)建對象是程序低效的一個重要原因。那么相同的字符串值能否在堆中只創(chuàng)建一個String對象那。顯然拘留字符串能夠做到這一點,除了程序中的字符串常量會被JVM自動創(chuàng)建拘留字符串之外,調用String的intern()方法也能做到這一點。當調用intern()時,如果常量池中已經有了當前String的值,那么返回這個常量指向拘留對象的地址。如果沒有,則將String值加入常量池中,并創(chuàng)建一個新的拘留字符串對象。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容