1. 程式人生 > >JDK原始碼分析系列---String,StringBuilder,StringBuffer

JDK原始碼分析系列---String,StringBuilder,StringBuffer

1.String

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {

    //儲存字元,final修飾
    private final char value[];

    //快取hash code,預設0
    private int hash;

    //序列號
    private static final long serialVersionUID = -6849794470754667710L;

    //宣告可序列化欄位
    private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];
}

1.1 基本屬性

  • char value[],用來儲存字串物件的字元陣列
  • int hash,用來快取字串的hash code,預設值為0
  • long serialVersionUID,用來序列化的序列版本號
  • ObjectStreamField[],可序列化類的欄位說明

1.2 常用構造器

public String() {
    this.value = "".value;
}

初始化新建立的物件,表示空字串""。請注意,此建構函式是不需要使用的,因為字串是不可變的
String str = new String(); 本質上是建立了一個空的字元陣列,str的長度為0

public String(String original) {
    this.value = original.value;
    this.hash = original.hash;
}   

初始化新建立的物件,表示和引數一樣的字串,換句話說是建立了和引數一樣的物件副本,除非需要顯示的宣告副本,否則該建構函式是不需要的,因為字串是不可變的

public String(StringBuffer buffer) {
    synchronized(buffer) {
    this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
    }
}

把StringBuffer的內容複製到String物件中,隨後修改StringBuffer物件的值,並不會影響String物件

public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}

把StringBuilder的內容複製到String物件中,隨後修改StringBuilder的值,並不會影響String物件;
此建構函式是為了把StringBuilder轉移到String物件,但是推薦使用StringBuilder的toString()方法,因為執行更快

1.3 常用方法

//返回字串的長度
public int length() {
    return value.length;
}

//比較兩個String值是否相等
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

//生成hash code
public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}
equals方法的判斷流程:
  • 首先判斷兩個物件是否相同,若相同返回true;若不同,下一步
  • 判斷引數是否為String物件,若不是,返回false;若是,下一步
  • 判斷兩個String的長度是否相等,若不是,返回false;若是,下一步
  • 按字元陣列索引依次比較字元,如果有任一不相同,返回false,否則返回true

1.2 為什麼說String是不可變物件?

  • 儲存字元的陣列value[]是final修飾的,值不可更改.

2. AbstractStringBuilder

可變的字元序列,StringBuilder和StringBuffer都繼承了該類,要了解StringBuilder和StringBuffer首先先了解AbstractStringBuilder.

2.1 基本屬性

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;
}
  • char[] value:儲存字元的陣列
  • int count:使用的字元的數量

2.2 構造器

/**
 * 無參構造器,用於子類序列化
 */
AbstractStringBuilder() {
}

/**
 * 指定字元陣列容量
 */
AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

2.3 常用方法

/**
 * 返回字元的數量
 */
@Override
public int length() {
    return count;
}

/**
 * 返回當前可儲存字元的最大數量,即容量
 */
public int capacity() {
    return value.length;
}

/**
 * 保證當前容量大於等於指定的最小數量minimumCapacity,會呼叫擴容方法
 */
public void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > 0)
        ensureCapacityInternal(minimumCapacity);
}

/**
 * 擴容,只有minimumCapacity大於當前容量,才會copy陣列擴容
 */
private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
                newCapacity(minimumCapacity));
    }
}
/**
 * 當前物件拼接字串str
 * 如果引數為null,那麼最終字串為"null",如果引數型別為boolean,那麼返回的是"true"或"false"
 * 例1: "abc".append(null) = "abcnull"
 * 例2: "abc".append("def") = "abcdef"
 */
public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

3. StringBuilder

可變的字元序列,非執行緒安全,StringBuilder和StringBuffer的實現方法很相似,區別在於是否執行緒安全,在單執行緒的情況下可使用StringBuilder,因為它比StringBuffer執行更快.StringBuilder繼承了AbstractStringBuilder類.

3.1 基本屬性

繼承父類

3.2 構造器

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

/**
 *序列號
 */
static final long serialVersionUID = 4383685877147921099L;

/**
 * 預設容量16
 * initial capacity of 16 characters.
 */
public StringBuilder() {
    super(16);
}

/**
 * 指定初始容量
 */
public StringBuilder(int capacity) {
    super(capacity);
}

/**
 * 把String字串初始化到物件中,容量變為str的長度+16
 */
public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
}

/**
 * 把字元初始化到物件中,容量變為字元的長度+16
 */
public StringBuilder(CharSequence seq) {
    this(seq.length() + 16);
    append(seq);
}

3.3 常用方法

同父類

4. StringBuffer

可變的字元序列,執行緒安全,StringBuffer繼承了AbstractStringBuilder類.

4.1 基本屬性

繼承父類,同時還有以下屬性

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

    /**
     * 最後一次呼叫toString返回值的快取
     * 當StringBuffer被修改時該快取被清除
     */
    private transient char[] toStringCache;

    /** 序列號 */
    static final long serialVersionUID = 3388685877147921107L;
}

4.2 構造器

同StringBuilder

4.3 常用方法

與StringBuilder方法基本相同,區別在於在StringBuilder的方法上加了synchronized鎖. 不同的地方還有以下這種情況

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}
@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

每次呼叫toString的時候,都會建立一個快取toStringCache,在每次修改物件的時候清空快取,但是這裡的快取具體什麼作用呢?大家可以在評論區留言!

5.總結

綜上所述,可以得出相同點是:都可以建立字串,不同在於String是不可變的,不存線上程安全問題;StringBuilder和StringBuffer字串是可變的,StringBuilder執行緒不安全,適合單執行緒使用,StringBuffer執行緒安全,適合多執行緒;對於頻繁需要字串的拼接操作時,不建議使用String,因為每次都需要建立一個String對