从源码看String,StringBuffer,StringBuilder的区别

前言

  看了一篇文章,大概是讲面试中的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非线程安全。可以根据他们不同的特性分情况使用。

 

posted @ 2018-03-13 16:54  丶Pz  阅读(179)  评论(0编辑  收藏  举报