亲宝软件园·资讯

展开

String、StringBuilder、StringBuffer 的理解 浅析我对 String、StringBuilder、StringBuffer 的理解

谨丰 人气:0

StringBuilder、StringBuffer 和 String 一样,都是用于存储字符串的。

1、那既然有了 String ,为什么还需要他们两个呢?

原因是 String 是不可变的,它每次的字符串拼接,实际上都会 new 一个新的 String 进行接收。

2、谈谈StringBuilder、StringBuffer他们两个的联系:

我们可以知道 StringBuffer 在 1.0 的时候就发布了,那为什么还需要 StringBuilder 呢?原因是它的大部分方法都上了锁,是线程安全的,导致了效率较低!而我们有时候不需要考虑线程安全问题,追求效率!所以 StringBuilder 在 1.5 的时候就出来了!

3、StringBuilder、StringBuffer 的异同:*

不同:

相同:内部方法和 StringBuffer 完全一致,因为都继承了 AbstractStringBuilder,底层数组都是用父类的。

4、源码浅析 String:

结论:final 修饰了底层的字符数组,故内容不可变。

5、源码浅析 StringBuilder:构造方法

观察构造方法:

 public StringBuilder() {
    super(16);
  }

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

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

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

结论:可以看出,它有一个默认的长度 16!而当传入参数是一个字符或者字符串时,它也会自动的传入参数的长度上加上 16!

6、源码浅析 StringBuilder:append 方法

 @Override
  public StringBuilder append(Object obj) {
    return append(String.valueOf(obj));
  }

  @Override
  public StringBuilder append(String str) {
    super.append(str);
    return this;
  }

我们发现,它还是调用的父类的 append 方法,说明这个方法他并没有重写,那么 StringBuffer 也一样!

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

结论:我们可以看出,他也是可以拼接 null 的!

 private AbstractStringBuilder appendNull() {
    int c = count;
    ensureCapacityInternal(c + 4);
    final char[] value = this.value;
    value[c++] = 'n';
    value[c++] = 'u';
    value[c++] = 'l';
    value[c++] = 'l';
    count = c;
    return this;
  }

然后观察,它接着进行了一个数组容量的判断,而数组的扩容,其实就是在里面实现的,我们点进去看一下!

 private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
      value = Arrays.copyOf(value,
          newCapacity(minimumCapacity));
    }
  }

结论:它先是判断,当前数组容量+拼接字符 是否大于 数组长度,如果大于,则进行数组拷贝,并将底层数组的引用指向新数组!

private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int newCapacity = (value.length << 1) + 2;
    if (newCapacity - minCapacity < 0) {
      newCapacity = minCapacity;
    }
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
      ? hugeCapacity(minCapacity)
      : newCapacity;
  }

结论:由此可见,新数组长度扩容为原数组的 2倍+2 !

问题:那它究竟是怎么拼接字符串的呢?

sb.getChars(0, len, value, count);

进去看一下:String 的 getChars 方法

 public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
  {
    if (srcBegin < 0)
      throw new StringIndexOutOfBoundsException(srcBegin);
    if ((srcEnd < 0) || (srcEnd > count))
      throw new StringIndexOutOfBoundsException(srcEnd);
    if (srcBegin > srcEnd)
      throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
  }

实际调用了一个系统类方法:arraycopy,再点进去看一下!

 public static native void arraycopy(Object src, int srcPos,
                    Object dest, int destPos,
                    int length);

结论:底层最终是调用的本地方法,实现了的字符数组拷贝,但由于本地方法是可以和操作系统直接打交道的,所以它的 append 字符串拼接效率会高于 String!

总结

加载全部内容

相关教程
猜你喜欢
用户评论