StringBuilder源码解析

签名(signature)

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

简介:可变的字符序列
StringBuilder使用了
-标记虚拟类AbstractStringBuilder
-标记接口java.io.Serializable,
-标记接口 CharSequence

AbstractStringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence 

简介:

一个可变的字符序列
执行了可变字符串。
在任何一个时间点,它包含一些特定的字符序列,但该序列的长度和内容可以通过某些方法调用。

AbstractStringBuilder的方法

AbstractStringBuilder的实例变量作用

AbstractStringBuilder使用了的接口

-标记接口 Appendable
-标记接口 CharSequence

接口Appendable
简介:

一个可以字符序列化和可加值的对象。添加接口必须通过实现java.util.Formatter格式化输出的类来实现。
被添加的字符应该由unicode编码进行编码。
添加对多线程访问不一定是安全的。线程安全是扩展和实现此接口类的责任
由于该接口可以实现由现有类不同风格的错误处理是没有保证的错误将被传播到调用程序。

接口CharSequence
简介:

字符序列是一个可读的字符序列。此接口针对不同的字符序列提供了统一的只读访问权限。一个char值代表在基本多文种平面字符(BMP)或替代。两个字符串对象比较的结果总体来讲是不确定的,每个类都将不能够测试它的实例与其他的平等。

问题:

为什么AbstractStringBuilder已经标记了CharSequcen接口,但是StringBulider 又标记了CharSequence ?
为什么标记两次?
猜想:为了强制实现CharSequence接口的方法

成员变量

static final long serialVersionUID = 4383685877147921099L
在进行反序列化时,JVM会把传来 的字节流中的serialVersionUID与本地相应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的, 可以进行反序列化,否则就会出现序列化版本不一致的异常——上次项目某位的原话。话说应该是小斌哥

源码剖析

构造器

提供了四个构造器

StringBuilder()

public StringBuilder() {
     super(16);
 }

使用了super();
其父类:

  AbstractStringBuilder(int capacity) {
      value = new char[capacity];
  }

创建了一个16位的字符数组。

StringBuilder(String str)

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

依旧调用了其父类AbstractStringBuilder(int capacity)的构造器。
创建了一个str.length()+16位的字符数组。
append()放在后文。

StringBuilder(int)

StringBuilder(CharSequence seq)

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

构造器总结:

全部指向了super(int);即AbstractStringBuilder(int);创建了相应长度的字符数组。

方法

append系列

append系列有14个重载方法
append系列
要分析StringBuilder的append系列,就要先分析一下AbstractStringBuilder

AbstractStringBuilder的append系列

该方法有13种重载方法
设计模式:策略模式——封装算法。这样用让算法独立于使用它们的客户。
这个系列的设计思路是:
先调用ensureCapacityInternal方法。
再根据不同参数进行操作。

ensureCapacityInternal方法:

ensureCapacityInternal(该方法线程不同步)
private void More …ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}

ensureCapacityInternal方法调用了expandCapacity(int)方法

void More ...expandCapacity(int minimumCapacity) {
         int newCapacity = value.length * 2 + 2;
         if (newCapacity - minimumCapacity < 0)
             newCapacity = minimumCapacity;
         if (newCapacity < 0) {
             if (minimumCapacity < 0) // overflow
                 throw new OutOfMemoryError();
             newCapacity = Integer.MAX_VALUE;
         }
         value = Arrays.copyOf(value, newCapacity);
     }

这个才是扩充容量的幕后英雄。
newCapacity是新数组的容量。

 value = Arrays.copyOf(value, newCapacity);

这句还将数组进行了复制。

AbstractStringBuilder append(char[] str)
public AbstractStringBuilder append(char[] str) {
     int len = str.length;
     ensureCapacityInternal(count + len);
     System.arraycopy(str, 0, value, count, len);
     count += len;
     return this;
 }

-int count——已建立的char数组的长度。

-ensureCapacityInternal(int)方法——确保char数组有足够大的地方存放新数组,并进行了copy

问题:
既然ensureCapacityInternal方法已经使用了ArrayCopy.arrayCopy,为什么还要继续使用System.arrayCopy?

StringBuilder的append系列
append(long long)
public StringBuilder append(long lng) {
    super.append(lng);
    return this;
}

insert系列

这里写图片描述
设计模式:装饰者模式?
区别:装饰者模式是接口,这个是将insert(int, int)转到insert(offset, String.valueOf(l));
设计思路;
最终都要集中到super.insert()上

StringBuilder的insert系列

insert(int, int)转到insert(offset, String.valueOf(l));

public StringBuilder More …insert(int offset, String str)

 public StringBuilder More ...insert(int offset, char[] str) {
        super.insert(offset, str);
        return this;
    }
AbstractStringBuilder的insert系列:

这里写图片描述
问题:
这里的inset(int,int类)依旧转成了insert(int offset, String str),为啥子类转一遍,父类还要再来一遍?尴尬???

public AbstractStringBuilder More …insert(int offset, String str)
public AbstractStringBuilder More ...insert(int offset, String str) {
         if ((offset < 0) || (offset > length()))
             throw new StringIndexOutOfBoundsException(offset);
         if (str == null)
             str = "null";
         int len = str.length();
         ensureCapacityInternal(count + len);
         System.arraycopy(value, offset, value, offset + len, count - offset);
         str.getChars(value, offset);
         count += len;
         return this;
     }

总结

可变性:

由ensureCapacityInternal和expandCapacity组合实现。具体情境看上方。
它没有像String那样重新new了一个char[],它仅仅在原有的handle上重新赋值。

#

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值