從原始碼看String,StringBuffer,StringBuilder的區別

丶Pz發表於2018-03-13

前言

  看了一篇文章,大概是講面試中的java基礎的,有如題這麼個面試題。我又翻了一些文章看了下,然後去看原始碼。看一下原始碼大概能更加了解一些。

String

  String類是final的,表示不可被繼承,不可變的。註釋上也有說明:

 

  

  其中用一個char[]來儲存String的值。

 private final char value[];

  一旦賦值,就不可改變。看一下,操作string的原始碼,例如 substringreplaceconcat 等方法,最終結果都是返回 new String(...). 也就是重新建立了一個String物件。

 public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }

  

public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }

  

public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

StringBuffer 和 StringBuilder

  它兩個都是繼承自 AbstractStringBuilder 抽象類,不同的是StringBuffer類都是帶有 synchronized 關鍵字的。也就是說,StringBuffer是執行緒安全的,而 StringBuilder不是。他們中的方法基本上呼叫 super的方法。也就是AbstractStringBuilder 裡實現的方法

  平時用的比較多的就是 append 方法。我們看一下程式碼實現:

 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;
    }

  

private void ensureCapacityInternal(int minimumCapacity) {
        // 當append之後的長度大於當前value的長度的時候,需要重新生成一個char[]陣列。
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

 

 public static char[] copyOf(char[] original, int newLength) {
     //重新建立一個char[]陣列 char[] copy = new char[newLength];
    //將之前的值賦值到該陣列中 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }

  

 ensureCapacityInternal 方法中,將 value的值重新擴充套件比如  str.append("abc")。假如之前value的值為:{'h','e','l','l','o'},當呼叫 str.getChars方法之後,會將 abc 追加到value陣列後,value值就變成 :{'h','e','l','l','o','a','b','c'}

 其實 getChars 方法只是做了一件事情 :System.arraycopy。

 如圖:

 執行完arraycopy之後

總結

  String 不可變,StringBuffer和StringBuilder可變,但是StringBuilder非執行緒安全。可以根據他們不同的特性分情況使用。

 

相關文章