[Java String] StringBuilder类解读

来源:互联网 发布:中国超级高铁计划知乎 编辑:程序博客网 时间:2024/06/05 23:06

首先我们来看一看其UML图
这里写图片描述

由关系图可知,StringBuilder类继承AbstractStringBuilder抽象类,而AbstractStringBuilder实现了AppendableCharSequence接口。
所以我们来看看这两个接口的定义和文档

CharSequence介绍

文档:

CharSequencechar值的只读序列(说白了就是char数组,并且该接口只提供了读方法,没提供写方法)。此接口对许多不同种类的的char序列提供统一的只读访问。

此接口没有重新定义equalshashCode。因此,两个实现了CharSequence接口的对象的比较结果也没有被定义。每个对象都可通过一个不同的类实现,而且不能保证每个类能够测试其实例与其他类的实例的相等性。因此,使用任意CharSequence实例作为集合中的元素或映射中的键是不合适的。

该接口定义的方法(不包含JDK1.8新增加的方法):

int length(); //此序列中char的数量char charAt(int index); //指定索引的char值CharSequence subSequence(int start, int end); //返回子字符序列public String toString(); //返回字符序列的字符串

上述四个方法验证了文档里说明的,此接口只提供了读操作,没有提供写操作(写操作一般都由具体的实现类定义实现)。

Appendable 介绍

文档:

能够被添加char序列和值的对象。如果某个类的实例打算接收来自Formatter的格式化输出,那么该类必须实现Appendable接口。

要添加的字符应该是有效的Unicode字符,正如 Unicode Character Representation 中描述的那样。注意,增补字符可能由多个 16 位 char 值组成。

Appendable对于多线程访问而言没必要是安全的。线程安全由扩展和实现此接口的类负责。

由于此接口可能由不同的已存在的具有不同错误处理风格的类实现,所以无法保证错误不会传播给调用者。

该接口定义的方法

Appendable append(CharSequence csq) throws IOException; //追加csqAppendable append(CharSequnce csq, int start, int end)  throws IOException; 追加csq的子序列Appendable append(char c) throws IOException; //追加一个字符

抽象类AbstractStringBuilder介绍

文档:

一个可变的字符序列
实现了可变的字符串。在任何时间这个字符串包含指定的字符序列,但是序列的内容和长度可以通过必要的方法调用而改变。
额外的注意:给构造器或方法传入null作为参数将会引发NullPointerException异常

该抽象类定义的成员变量:

char[] value;  //用于存取字符的字符序列int count; //存在字符的数量

该抽象类定义的构造器:

//因为下面提供了有参构造器,所以提供一个无参构造器供子类序列化使用AbstractStringBuilder(){}//创建一个具有指定容量的实现(容量,也就是数组的长度)AbstractStringBuilder(int capacity){    value = new char[capacity];}

该抽象类的实现和定义的方法:

@overridepublic int length(){    return count; //返回的是value[]数组中,存在的字符数量,而不是value[] 的长度}//关于容量的几个方法://获取容量public int capacity(){    return value.length //返回数组的长度,数组的长度代表了此类的容量,因为使用value数组存储字符}//确定此类的容量到少和指定的最小值相等。//如果当前的容量少于给定的参数(也就是minimumCapacity),随后一个新的内部数组被重新分配具有更大的容量//新的容量大于:原始容量 * 2 + 2//如果minimumCapacity参数是非正数,此方法简单的返回,不采取任何行动。//注意后序的操作能减少真实的容量(指的是trimToSize())public void ensureCapacity(int minimumCapacity){    if(minimumCapacity > 0){        ensureCapacityInternal(minimumCapacity);    }} //确保给定的容量参数大于数组的长度(也就是原容量) public void ensureCapacityInternal(int minimumCapacity){    if(minimumCapacity - value.length > 0){        expandCapacity(minimumCapacity);    }}//扩容数组void expandCapacity(int minimumCapacity){    //将value.length *2 + 2 与 minimumCapacity 相比较取两者之间最大的值    int newCapacity = value.length * 2 + 2;    if(newCapacity - minimumCapacity < 0)        newCapacity = minmumCapacity;    //如果newCapacity小于0,说明数值过大越界抛出异常    if(newCapacity < 0){        if(minimumCapacity < 0){            throw new OutOfMemoryError();        newCapacity = Integer.MAX_VALUE;    }    //执行到这里一切正常,扩容数组    value = Arrays.copyOf(value, newCapacity);}//将容量减少到与count相等public void trimToSize(){    if(count < value.length){        value = Arrays.copyOf(value, count);    }}//如果newLength 大于count将数组扩容,并以'\0'填充public void setLength(int newLength){    if(newLength < 0)        throw new StringIndexOutOfBoundsException(newLenght);    ensureCapacityInternal(newLength);    if(count < newLength){        Arrays.fill(value,count,newLength, '\0');    }    count = newLength;}//像数组一样返回指定索引的字符@Overridepublic char charAt(int index){    if((index < 0) || (index >= count))        throw new StringIndexOutOfBoundsException(index);    return value[index];}//一系列越界检查,将此类的value指定位置的字符序列拷贝到给定的字符数组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    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);}//将指定索引设置为ch,包装了一个数组操作public void setCharAt(int index, char ch){    if((index < 0) || (index >= count))        throw new StringIndexOutOfBoundsException(index);    value[index] = ch;}
//一系列的append的方法public AbstractStringBuilder append(Object obj){    return append(String.valueOf(obj));}public AbstractStringBuilder append(String str){    //如果字符串为null,追加字符串"null"    if(str == null)        return appendNull();    //确保容量    //将String内部的数组拷贝到此类的内部数组    //增加count计数    int len = str.length;    ensureCapacityInternal(count + len);    str.getChars(0, len, value, count);    count += len;    return this;}public AbstractStringBuilder append(CharSequence s){    //如果为null 就调用appendNull()其实就是追加"null"    if(s == null)        return appendNull();    if(s instanceof String)        return this.append((String)s);    if(s instanceof AbstractStringBuilder))        return this.append((AbstractStringBuilder)s);    return this.append(s, 0, s.length());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;}@Overridepublic AbstractStringBuilder append(CharSequence s, int start, int end){    if(s == null)        s = "null"    if((start < 0) || (start > end) || (end > s.length()))        throw new IndexOutOfBoundsException(            "start" + start + ", end" + end + ", s.length() "            + s.length());    int len = end - start;    ensureCapacityInternal(count + len);    for(int i = start, j = count; i < end; i++, j++)        value[j] = s.charAt(i);    count += len;    return this;            }public AbstractStringBuilder append(char[] str){    int len = str.length;    ensureCapacityInternal(count + len);    System.arraycopy(str, 0, value, count, len);    count += len;    return this;}public AbstractStringBuilder append(char str[], int offset, int len){    if(len > 0)        ensureCapacityInternal(count + len);    System.arraycopy(str, offset, value, count, len);    count += len;    return this;}public AbstractStringBuilder append(boolean b){    if(b){        ensureCapaciptyInternal(count + 4);        value[count++] = 't';        value[count++] = 'r';        value[count++] = 'u';        value[count++] = 'e';    } else {        ensureCapacityInternal(count + 5);        value[count++] = 'f';        value[count++] = 'a';        value[count++] = 'l';        value[count++] = 's';        value[count++] = 'e';    }    return this;}@Overridepublic AbstractStringBuilder append(char c){    ensureCapacityInternal(count + 1);    value[count++] = c;    return this;}//追加数值的一些操作public AbstractStringBuilder append(int i){    if(i == Integer.MIN_VALUE){        append("-2147483648");        return this;    }    int appendedLength = (i < 0) ? Integer.stringSize(-i) + i                        : Integer.stringSize(i);    int spaceNeeded = count + appendedLength;    ensureCapacityInternal(spaceNeed);    Integer.getChars(i, spaceNeeded, value);    count = spaceNeed;    return this;}public AbstractStringBuilder append(long l){    if(l == Long.MIN_VALUE){        append("-9223372036854775808");        return this;    }    int appendedLength = (l < 0)?Long.stringSize(-1) + 1                                : Long.stringSize(l);    int spaceNeeded = count + appendedLength;    ensureCapacityInternal(spaceNeeded);    Long.getChars(l, spaceNeeded, value);    count = spaceNeeded;    return this;}public AbstractStringBuilder append(float f){    FloatingDecimal.appendTo(f, this);    return this;}public AbstractStringBuilder append(double d){    FloatingDecimal.appendTo(d, this);    return this;}       

append操作的一些总结:

  1. append的本质就是内部value[] 字符类型的数值作为存储媒介,数组的长度就是该类的容量,字符的数量就是该类的length()返回的长度。
  2. 3个保证容量的方法来保证存储空间
  3. append 在追加操作完成之后,返回this,所以支持连缀操作
  4. append每次执行都会确保容量,在进入expandCapacity方法之后,内部的value[]数组就会扩容
  5. append可收的参数包括字符,字符序列,字符串,StringBuffer, AbstractStringBuilder,和一些基本类型
public AbstractStringBuilder delete(int start, int end){    //一系列的越界检查    if(start < 0)        throw new StringIndexOutOfBoundsException(start);    if(end > count)        end = count;    if(start > end)        throw new StringIndexOutOfBoundsException();    if(len > 0){        //拷贝数组        System.arrarycopy(value, start + len, value, start, count - end);    }    return this;}public AbstractStringBuilder deleteCharAt(int index){    if(index < 0 || index >= count){        throw new StringIndexOutOfBoundsException(index);    System.arraycopy(value, index + 1, value, index, count-index-1);    count--;    return this;}public AbstractStringBuilder replace(int start, int end, String str){    if(start < 0)        throw new StringIndexOutOfBoundsException();    if(end > count)        end = count;    if(start > end)        throw new StringIndexOutBoundsException();    int len = str.lenth();    int newCount = count + (len - (end - start);    System.arrayCopy(value, end, value, start + len, count - end);    String.getChars(value, start);    count = newCount;    return this;}public String subString(int start){    return subString(start, count);}public String subString(int start, int end){    if(start < 0)        throw new StringIndexOutOfBoundsException(start);    if(end > count)        throw new StringIndexOutOfBoundsException(end)    if(start > end){        throw new StringIndexOutOfBoundsException(end - start);    return new String(value, start, end - start);}public CharSequence(int start, int end){    reuturn subString(start, end);}

//一大堆的重载方法

//核心方法是下面这个方法,其他方法都是对此方法的包装public AbstractStringBuilder insert(int index, char[] str, int offset, int len){    if((index < 0 || (index > length()))        throw new StringIndexOutOfBoundsException(index);    if(offset < 0 || (len < 0) || (offset > str.length - len))        throw new StringIndexOutOfBoundsException(        "offset " + offset + ", len" + len + ", str.length "        + str.length);    ensureCapacityInternal(count + len);    System.arraycopy(value, index, value, index + len, count - index);    System.arraycopy(str, offset, value, index, len);    count += len;    return this;} 

//indexOf lastIndexOf其实是对String.indexOf的包装

public int indexOf(String str){    return indexOf(str, 0);}public int indexOf(String str, int fromIndex){    return String.indexOf(value, 0, count, str, fromIndex);}public int lastIndexOf(String str){    return lastIndexOf(Str, count);}public int lastIndexOf(String str, int fromIndex){    return String.lastIndexOf(value, 0, count, str, fromIndex)

返回内部字符数组的方法

final char[] getValue(){    return value;}

还有reverse()是反转字符的操作,表示没有看懂,就不再此展示了。

StringBuilder类

分析完上述的StringBuilder的父类和接口,再来看StringBuilder类其实就很简单了

文档:

一个可变字符序列。此类提供的APIStringBuffer提供的一样,但不保证线程安全,此类的设计目的是在单线程环境下代替StringBuffer。因为在大多实现下,此类要比StringBuffer快。
StringBuilder的核心操作是append()和insert()(一大堆的重载操作,能不是核心吗)
这此方法被重载可以接受任何类型。每个方法都高效的把给定的参数转换为字符串然后追加或插入其字符到StringBuilder里

定义的方法

方法在这里不过多介绍,其实都是调用AbstractStringBuilder类的对应方法
唯一要注意的是实现了AbstractStringBuilder类定义的抽象方法toString()

@Overridepublic String toString(){    return new String(value, 0, count);}
1 1