百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

你学习Java那么多年了,却还不知道AbstractStringBuilder类源码

toyiye 2024-09-07 00:39 3 浏览 0 评论

文/小图灵视界

本头条号将会继续分析JDK8的源码,欢迎关注和收藏,也会将分析笔记开源。

位置:java.lang

大家都知道Java中的String是不可变的,StringBuffer类和StringBuilder类是可变的。而AbstractStringBuilder类是StringBuffer类和StringBuilder类的父类,也是可以可变的类,AbstractStringBuilder类的定义如下:

abstract class AbstractStringBuilder implements Appendable, CharSequence 

AbstractStringBuilder类是抽象类,实现了Appendable和CharSequence接口,可进行添加操作和CharSequence序列相关操作。Appendable接口的方法如下:

//将序列添加在字符串上
Appendable append(CharSequence csq) throws IOException;
//从start位置到end位置的csq子字符添加到字符串
Appendable append(CharSequence csq, int start, int end) throws IOException;
//将字符c添加到字符串中
Appendable append(char c) throws IOException;

属性

//用来保存字符的char数组
char[] value;
//表示有多少用了多少容量(字符的个数),表示value数组中存储字符的数量
int count;
//AbstractStringBuilder类最大数组长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

AbstractStringBuilder类是抽象类,所以它的所有属性默认都是使用public修饰,value属性用来保存字符串,count表示value数组中存储字符的数量。与String中value不同,AbstractStringBuilder的value数组是可以改变的。MAX_ARRAY_SIZE是可容纳的最大字符的长度。

构造器

//没有参数的构造器
AbstractStringBuilder() {}
//给定容量的构造器
AbstractStringBuilder(int capacity) {
      value = new char[capacity];
}

AbstractStringBuilder类有两个构造器,一个无参构造器,一个给定容量capacity的构造器,这个构造器创建capacity大小的char数组。

常用方法

//返回value数组中存储字符的数量
public int length() {
      return count;
}
//返回value数组的容量大小
public int capacity() {
     return value.length;
}

length() 方法返回的是value数组中存储字符的实际数量, capacity() 返回的是value数组的容量大小。当value数组中都存储满了字符,那么length()和capacity()返回的值相等,否则,capacity()的返回值大于length() 的返回值。

//扩容
public void ensureCapacity(int minimumCapacity) {
     if (minimumCapacity > 0)
          ensureCapacityInternal(minimumCapacity);
}
//实际扩容方法
private void ensureCapacityInternal(int minimumCapacity) {
      // overflow-conscious code
      if (minimumCapacity - value.length > 0) {
          value = Arrays.copyOf(value,newCapacity(minimumCapacity));
      }
}

ensureCapacity(int minimumCapacity)方法的作用是扩容数组,当minimumCapacity大于0时,调用ensureCapacityInternal(int minimumCapacity)方法。

当ensureCapacityInternal(int minimumCapacity)方法的minimumCapacity参数大于value数组的长度时,通过Arrays.copyOf方法复制字符串到扩容的新的数组中,然后再赋值给value数组。

在调用Arrays.copyOf方法时,调用了newCapacity(int minCapacity)方法,这个方法就是实际扩容数组大小的的方法。newCapacity(int minCapacity)定义如下:

//返回新的数组长度的大小
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;
}

private int hugeCapacity(int minCapacity) {
      if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
          throw new OutOfMemoryError();
      }
      return (minCapacity > MAX_ARRAY_SIZE)? minCapacity : MAX_ARRAY_SIZE;
 }

newCapacity(int minCapacity)方法首先将原来char数组value的长度扩大2倍加2((value.length << 1) + 2),得到新的长度newCapacity,当newCapacity小于传入的参数minCapacity时,将minCapacity赋值给newCapacity。当newCapacity小于等于0或者newCapacity大于MAX_ARRAY_SIZE时,调用 hugeCapacity(int minCapacity) 方法扩容,否则返回newCapacity。

hugeCapacity(int minCapacity)方法,当minCapacity大于Integer.MAX_VALUE时,抛出越界OutOfMemoryError异常,如果minCapacity大于MAX_ARRAY_SIZE,返回minCapacity,否则返回MAX_ARRAY_SIZE。

public void trimToSize() {
      if (count < value.length) {
          value = Arrays.copyOf(value, count);
       }
}

trimToSize()方法调整value数组的容量大小,当数组value中保存的实际字符大小count小于数组value的容量时,将value数组中的大小复制给容量大小为count的新创建的数组中,然后将新的数组赋值给value,这时capacity()方法返回的值和 length()返回的值一样大小。这个方法可能会改变capacity()方法返回的值,即原来value数组的容量大小。

public void setLength(int newLength) {
    	//如果是负数,抛出异常
        if (newLength < 0)
            throw new StringIndexOutOfBoundsException(newLength);
    	//newLength大于value.length时,复制数组进行扩容
        ensureCapacityInternal(newLength);
		//当数组存储字符的数量count小于newLength,对数组填充'\0'
        if (count < newLength) {
            Arrays.fill(value, count, newLength, '\0');
        }
		//将当数组存储字符的数量count设置为newLength
        count = newLength;
}

setLength(int newLength) 方法设置字符序列的长度。当newLength参数小于字符串value数组的长度,数组存储字符的数量count被设置为newLength。当newLength参数大于字符串value数组的长度,首先调用ensureCapacityInternal方法对字符串的原数组value进行扩容,然后判断下数组存储字符的数量count是否小于newLength,如果是的话,将数组count索引以后的位置用‘\0’填充,最后将count设置为newLength。

public char charAt(int index) {
    //边界判断
     if ((index < 0) || (index >= count))
         throw new StringIndexOutOfBoundsException(index);
    //返回指定索引位置的值
     return value[index];
}

charAt(int index)方法的作用是返回指定索引位置的字符。首先进行边界判断,如果index小于0或者index大于等于数组value实际存储字符的数量count,则抛出StringIndexOutOfBoundsException异常。当index合法时,直接通过数组取index位置的值。

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

getChars方法的作用是将字符串的字符复制到指定的char数组中。getChars方法将value数组的srcBegin位置到srcEnd位置的字符串复制到char数组dst中dstBegin开始的位置。方法首先进行边界判断,当srcBegin小于0、srcEnd或者srcEnd大于count、srcBegin大于srcEnd时,抛出StringIndexOutOfBoundsException异常。当srcBegin、srcEnd、dstBegin都合法时,通过本地方法System.arraycopy进行复制字符到dst数组中。

public void setCharAt(int index, char ch) {
    //如果index小于0或者index大于等于count
     if ((index < 0) || (index >= count))
          throw new StringIndexOutOfBoundsException(index);
     value[index] = ch;
}

setCharAt方法的作用是将字符串某个index位置的值设置为给定的字符。/如果index小于0或者index大于等于实际存储字符的数量count,抛出StringIndexOutOfBoundsException异常。最后将字符ch直接赋值给value数组的index位置。

public AbstractStringBuilder append(String str) {
    	//添加空字符串
        if (str == null)
            return appendNull();
        int len = str.length();
    	//当count + len大于value.length时,进行扩容
        ensureCapacityInternal(count + len);
    	//将str字符串复制到value数组中
        str.getChars(0, len, value, count);
    	//数组实际存储字符的数量count添加str的长度
        count += len;
        return this;
}
private AbstractStringBuilder appendNull() {
        int c = count;
    	//当c+4大于value.length时,进行扩容
        ensureCapacityInternal(c + 4);
    	//将空字符串“null”添加到数组中。
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
        count = c;
        return this;
}

append(String str)方法将str字符串添加到原来字符串后面。如果参数str为null,执行appendNull()方法,appendNull方法首先将数组进行扩容,将空字符串“null”添加到数组中,当参数str不为null时,首先判断是否需要对数组进行扩容,当count + len大于value.length时,进行数组扩容。然后将str字符串复制到value数组中,更新数组实际存储字符的数量count,count的大小等于原来count的大小加上str字符串的长度len。

public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)
            return appendNull();
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
}
AbstractStringBuilder append(AbstractStringBuilder asb) {
        if (asb == null)
            return appendNull();
        int len = asb.length();
        ensureCapacityInternal(count + len);
        asb.getChars(0, len, value, count);
        count += len;
        return this;
}

append(StringBuffer sb)方法、append(AbstractStringBuilder asb)方法和append(String str)方法的逻辑一模一样,没什么好分析的了。

public AbstractStringBuilder append(CharSequence s) {
    	//添加空字符null
        if (s == null)
            return appendNull();
        if (s instanceof String)
            //当参数是String类型
            return this.append((String)s);
        if (s instanceof AbstractStringBuilder)
            //当参数是AbstractStringBuilder类型
            return this.append((AbstractStringBuilder)s);
		//一般的序列类型(CharSequence)
        return this.append(s, 0, s.length());
}
//实现Appendable接口的 append(CharSequence s, int start, int end)方法
public AbstractStringBuilder append(CharSequence s, int start, int end) {
    	//空字符“null”
        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;
    	//当count + len大于value.length时,进行扩容
        ensureCapacityInternal(count + len);
    	//遍历序列s,将序列的字符从start位置到end复制到value数组的count位置后
        for (int i = start, j = count; i < end; i++, j++)
            value[j] = s.charAt(i);
        count += len;
        return this;
}

append(CharSequence s)方法是将序列添加到字符串的后面,参数是CharSequence类型,当序列s为nulll时,调用appendNull()方法进行空字符“null”的添加;当序列s为String类型时,调用append(String str)方法;当序列s为AbstractStringBuilder时,调用append(AbstractStringBuilder asb)方法;当序列s只是一般的序列时,调用 append(CharSequence s, int start, int end)方法,该方法为Appendable接口的方法。

append(CharSequence s, int start, int end)方法针对一般的序列添加操作,首先判断序列s是否为null,然后进行边界判断,当count + len大于value.length时,进行数组扩容,最后遍历序列s,将序列的字符从start位置到end复制到value数组的count位置后,更新count的大小。

public AbstractStringBuilder append(char[] str) {
        int len = str.length;
    	//当count + len大于value.length时,进行扩容
        ensureCapacityInternal(count + len);
    	//数组复制
        System.arraycopy(str, 0, value, count, len);
    	//更新count的大小
        count += len;
        return this;
}
//从chat数组str的offset位置复制len个字符到value数组
public AbstractStringBuilder append(char str[], int offset, int len) {
        if (len > 0)                // let arraycopy report AIOOBE for len < 0
            ensureCapacityInternal(count + len);
        System.arraycopy(str, offset, value, count, len);
        count += len;
        return this;
}

append(char[] str)方法将char数组添加在字符串的后面。首先当count + len大于value.length时,进行数组的扩容,然后利用System.arraycopy方法将char数组str复制给value,最后更新数组实际存储字符的数量count。

//删除从start位置到end位置的字符串
public AbstractStringBuilder delete(int start, int end) {
    	//边界判断
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
    	//如果end大于count,将count赋值给end
        if (end > count)
            end = count;
        if (start > end)
            throw new StringIndexOutOfBoundsException();
        int len = end - start;
        if (len > 0) {
            //将value数组的start+len位置开始覆盖value的数组的start位置,覆盖count-end个字符
            System.arraycopy(value, start+len, value, start, count-end);
            count -= len;
        }
        return this;
}
//删除index位置的字符
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;
}

delete(int start, int end) 方法删除从start位置到end位置的字符。如果start小于0,抛出异常,如果end大于count,将count赋值给end。当start > end时,抛出异常。最后通过System.arraycopy复制方式将start位置到end位置的字符被start+len位置开始的字符覆盖,将count-end个字符往前移动,最后更新数组实际存储字符的数量count。deleteCharAt(int index)方法逻辑跟delete(int start, int end) 逻辑是一样的,都是通过System.arraycopy将某位置的字符覆盖前面的字符。

//将start到end位置的字符串替换为字符串str
public AbstractStringBuilder replace(int start, int end, String str) {
    	//边界判断
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (start > count)
            throw new StringIndexOutOfBoundsException("start > length()");
        if (start > end)
            throw new StringIndexOutOfBoundsException("start > end");

        if (end > count)
            end = count;
        int len = str.length();
    	//新的数组实际存储字符的数量count
        int newCount = count + len - (end - start);
    	//如果newCount大于value.length,进行数组扩容
        ensureCapacityInternal(newCount);
		//将end位置以后的字符串从start + len位置覆盖value数组,
    	//相当于空出len长度的位置,用来添加str字符
        System.arraycopy(value, end, value, start + len, count - end);
    	//将str字符添加在value数组中
        str.getChars(value, start);
    	//更新count
        count = newCount;
        return this;
}

replace(int start, int end, String str) 方法的作用将start到end位置的字符串替换为字符串str。首先进行边界判断,计算出新的数组实际存储字符的数量newCount,如果newCount大于value.length,进行数组扩容,然后通过System.arraycopy将end位置以后的字符串从start + len位置开始覆盖value数组,相当于空出len长度的位置,用来添加str字符。最后将str字符添加在value数组中,更新count。

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);
    	//当count + len大于value.length时,进行扩容
        ensureCapacityInternal(count + len);
    	//将index位置后的元素移动到index + len位置,移动count - index长度的元素
    	//相当于在index位置以后空出len长度的位置添加str字符
        System.arraycopy(value, index, value, index + len, count - index);
    	//在空出的len位置上添加str字符到value数组中
        System.arraycopy(str, offset, value, index, len);
    	//更新count
        count += len;
        return this;
}

insert(int index, char[] str, int offset,int len)方法的作用是从某个位置插入char数组,index表示插入char数组的位置,str吧表示插入的char数组,offset是str数组开始插入value数组的位置,len表示需要插入长度。方法首先进行边界判断,当count + len大于value.length时,进行数组扩容,然后通过System.arraycop将index位置后的元素移动到index + len位置,移动count - index长度的元素,相当于在index位置以后空出len长度的位置添加str字符,再次通过System.arraycopy在空出的len位置上添加str字符到value数组中,最后更新count。

//从offset位置插入str字符串
public AbstractStringBuilder insert(int offset, String str) {
        if ((offset < 0) || (offset > length()))
            throw new StringIndexOutOfBoundsException(offset);
        if (str == null)
            str = "null";
        int len = str.length();
    	//如果count + len大于value.length时,进行数组扩容
        ensureCapacityInternal(count + len);
    	//将offset位置开始的元素移动到offset + len开始的位置上,相当于空出len长度来插入str字符串
        System.arraycopy(value, offset, value, offset + len, count - offset);
    	//将str字符串复制给value数组
        str.getChars(value, offset);
    	//更新count
        count += len;
        return this;
}

insert(int offset, String str)方法的作用从offset位置插入str字符串。如果count + len大于value.length时,进行数组扩容,通过System.arraycopy方法将offset位置开始的元素移动到offset + len开始的位置上,相当于空出len长度来插入str字符串,然后通过将getChars方法将str字符串复制给value数组,最后更新count。

//从offset位置插入char数组str
public AbstractStringBuilder insert(int offset, char[] str) {
        if ((offset < 0) || (offset > length()))
            throw new StringIndexOutOfBoundsException(offset);
        int len = str.length;
    	//扩容
        ensureCapacityInternal(count + len);
    	//offset位置字符移动到offset + len位置,移动count - offset个元素
    	//相当于空出len长度的位置添加str数组
        System.arraycopy(value, offset, value, offset + len, count - offset);
    	//在空出的len长度添加str数组
        System.arraycopy(str, 0, value, offset, len);
    	//更新count
        count += len;
        return this;
}

insert(int offset, char[] str) 方法的作用是将从offset位置插入char数组str。如果count + len大于value.length时,进行数组扩容。然后通过System.arraycopy将offset位置字符移动到offset + len位置,移动count - offset个元素相当于空出len长度的位置添加str数组,再次通过System.arraycopy在空出的len长度添加str数组,最后更新count。

//由子类实现
public abstract String toString();
//获取value数组的方法
 final char[] getValue() {
        return value;
 }

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码