Stringbuilder原理以及StringBuffer

JAVA中String是不可变的,存放在字符串常量池中。当我们创建一个String时,它就已经是不可改变的了。
观察String源码可以知道String类封装的是char数组常量,因此长度、内容均不可变:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

那么String API中subString、replace返回的是什么呢?
substring:

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

replace:

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

String的API中不论是截取还是替换等操作都是返回一个新的String对象(JVM中会现在字符串常量池中寻找是否含有目的字符串)。

那么如果我们想动态改变String呢?如果使用传统的“+“或者是String API每次生成一个新的String对象,有时会浪费空间。

StrigBuilder 和StringBuffer便是动态改变字符串的类。

StringBuffer是StringBuiler类的多线程版本,两个类的API相同。StringBuffer类中含有对同步锁synchronized的判定,是线程安全的。所以StringBuilder用于单线程,StringBuffer用于多线程。这里重点介绍StringBuilder。
(1)StringBuilder的用法:
首先,构建一个空的字符串构造器:
StringBuilder builder =new StringBuilder();//(调用了无参构造器)
当每次需要添加一部分内容时,就调用append方法。
builder.append(“H”);
builder.append(“E”);
builder.append(“LLO”);

在需要构建字符串时就调用toString方法,将可以得到一个String对象,其中包含了构建器中的字符序列。
String completedString=builder.toString();
最终completedString中内容为"HELLO"。

(2)StringBuilder的源码:

StringBuilder的类定义:StrigBuilder继承自AbstractStringBuilder

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

AbstractStringBuilder的源码:

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;//AbstractStringBuilder中用来是存放字符串的字符数组

    /**
     * The count is the number of characters used.
     */
    int count;//描述当前字符数组的实际容量(即数组内字符串长度)

    /**
     * This no-arg constructor is necessary for serialization of subclasses.
     */
    AbstractStringBuilder() {
    }

    /**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

由源码可知AbstractStringBuilder内部是可变数组,AbstractStringBuilder的构造函数确定了数组初始容量大小

StrigBuilder的构造函数直接调用了父类AbstractStringBuilder的构造函数,并

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

    /** use serialVersionUID for interoperability */
    static final long serialVersionUID = 4383685877147921099L;

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity of 16 characters.
     */
    public StringBuilder() {
        super(16);
    }

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity specified by the {@code capacity} argument.
     *
     * @param      capacity  the initial capacity.
     * @throws     NegativeArraySizeException  if the {@code capacity}
     *               argument is less than {@code 0}.
     */
    public StringBuilder(int capacity) {
        super(capacity);
    }

所以StringBuilder builder =new StringBuilder();一开始构建一个构造器,builder对象会初始化一个长度为16的char数组,内容为空。

当我们需要向builder中添加字符串时,使用append()方法。

StringBuilder的append源码(调用了父类AbstractStringBuilder的append方法):

    @Override
    public StringBuilder append(char[] str) {
        super.append(str);
        return this;
    }

AbstractStringBuilder的append方法源码:

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

调用了了ensureCapacityInternal()方法和array方法。ensureCapacityInternal(count + len)方法判断当前数组的实际容量加上要添加的字符串长度是否大于最大容量,如果大于最大容量,那么就扩容,扩容规则在方法内,扩容手段为Arrays.copyOf()。

    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }
	//当minimumCapacity(count+len,原实际长度加新增字符串长度)大于最大容量,就使用Arrays.copyOf方法延长数组容量,具体延长长度由newCapacity()方法确定。

然后利用System.arraycopy(str, 0, value, count, len)浅复制数组,达到添加字符串的目的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值