CharSequence相关源码学习

概述

该文档主要从源码角度学习CharSequence及相关内容(如SpannableStringSpannableStringBuilderStringStringBuilderStringBuffer等)的组织结构和实现

具体的组织结构可查看下图

基础接口

CharSequence

  1. 描述
    • char类型值的只读序列
    • 提供统一的只读的访问方法,如长度、某位置的值、子序列的获取等
    • hashCode()equals()方法使用注意:并未重写ObjecthashCode()equals()方法,因此无法对实现CharSequenc的类进行比较;同时每个对象可以被不同的类实现,无法保证每个类可以测试相互之间实例的等同性,所以不适合使用任意的CharSequence实例作为set的元素或map的键值
  2. 具体方法
Method Description
int length() 返回字符序列的长度
char charAt(int index) 返回指定位置处([0, length()-1])的char类型值
CharSequence subSequence(int start, int end) 返回指定范围([start, end)]的字符序列
String toString() 返回和这个序列相同的String类型值
IntStream chars() 默认方法(Java8才支持);返回这个序列char类型对应的int类型值的流
IntStream codePoints() 默认方法(Java8才支持);返回这个序列的code point值的流

Appendable

  1. 描述
    • 可以追加char序列和值
    • 若某实例想要接收Formatter格式化的输出,必须要实现Appendable接口
    • 追加的字符应该是有效的Unicode字符;注意增补字符可能由多个16位char值组成
    • Appendable对于多线程访问没必要是安全的,线程安全是继承或实现该接口的类的责任
    • 因为此接口可能由具有不同的错误处理风格的类实现,所以无法保证错误会传递给调用者
  2. 具体方法
Method Description
Appendable append(CharSequence csq) 追加指定的字符序列;依赖于实现字符序列csq的类,全部的序列可能不被追加,如java.nio.CharBuffer由缓存的位置和限制数决定;若csqnull,四个字符“null”会被追加
Appendable append(CharSequence csq, int start, int end) 追加指定字符序列位置处([start, end))的内容 ;若csqnull,四个字符“null”会被追加
Appendable append(char c) 追加指定的字符

Serializable

描述

  • Java提供了一种对象序列化的机制,即对象可以表示成字节序列(或字节流),包括对象的数据、对象的类型信息和存储在对象中的数据类型
  • 标记接口,没有方法或域
  • 没有实现该接口的类不会让任一个状态序列化或反序列化;序列化类的所有子类型都是可序列化的
  • 为允许非序列化类的子类型序列化,子类型可以承担保存和恢复父类型的publicprotectedpackage(如果可能的话)域的责任;子类型只有在继承类有可访问的无参构造函数初始化类的状态时,可以承担此责任
  • 反序列化期间,非序列化类的域会使用publicprotected的无参构造函数初始化
  • statictransient修饰的数据成员不可被序列化
  • 数组或集合中的序列化:要求数组中的所有对象或集合中的所有元素必须是可序列化的

使用

  • ObjectOutputStream:用于写基本的数据类型和Java对象到一个OutputStream;注意只有支持java.io.Serializable接口的对象可以被写入流
Method Description
ObjectOutputStream(OutputStream out) 创建一个写到指定输出流的ObjectOutputStream
final void writeObject(Object obj) 写指定的对象到ObjectOutputStream
void flush() 冲刷当前的输出流
void close() 关闭当前的输出流
  • ObjectInputStream:用于反序列化使用ObjectOutputStream写入的基本数据和对象
Method Description
ObjectInputStream(InputStream in) 创建一个从指定的输入流读取的ObjectInputStream
final Object readObject() 从输入流中读取一个对象
void close() 关闭当前的输入流

注意

  • 如果一个序列化类没有显示定义一个serialVersionUID,然后序列化运行时会根据这个类的多方面因素(正如Java对象序列化规范里描述的那样)计算一个默认的serialVersionUID
  • 然而强烈推荐所有的序列化类显示定义serialVersionUID值,因为默认的serialVersionUID计算是对可能随编译器实现变化的类的详情高度敏感的,因此在反序列化期间可能导致不可预料的InvalidClassException
  • 强烈建议显示的serialVersionUID定义尽可能使用private修饰,因为这样的只用在立即定义的类的serialVersionUID的域上的定义不能作为继承的成员使用
  • 数组类不能定义一个显示的serialVersionUID,所以数组只有默认的计算值
  • serialVersionUID计算的Android实现会在android N上随着一些类轻微变化,为了保证兼容性,极力推荐使用显示的serialVersionUID域来避免兼容性问题

Comparable

  1. 描述
    • 此接口强加全部的排序在实现该接口的每个类对象上;这种排序被称为自然排序,这个类的compareTo()方法被称为自然排序方法
    • 实现该接口的对象列表或数组可以通过Collections.sort()Arrays.sort()方法自动排序
    • 实现此接口的对象可以被用作排序map的键值或排序set的元素,没有必要指定一个comparator
    • 一个类的自然排序和equals()方法的一致性:有且仅有当compareTo()方法等于0,并且equals()方法等于true的时候;在排序map排序set中强烈推荐;实际上所有实现了Comparable接口的Java核心类都有和equals()一致的自然排序
    • null不是一个类,也不是一个对象,compareTo(null)方法会抛出NullPointerException,尽管equals(null)返回false
  2. 方法
Method Description
int compareTo(T o) 和指定的对象进行比较;负数表示小于,0表示等于,正数表示大于

具体接口或类

CharSequence衍生

GetChars

  1. 描述
    • 用途:若CharSequence的实现类有getChars()方法,可以实现该接口
    • 作用:比多次调用charAt()方法快得多
  2. 具体方法
Method Description
void getChars(int start, int end, char[] dest, int destoff) 将给定位置处([start, end))的内容拷贝到给定的数组dest中,其中起始位置是destoff

AlteredCharSequence

  1. 描述
    • 一个变化的CharSequence主要是另一个CharSequence的镜像,除了指定范围的字符是不同的字符数组的镜像
  2. public static AlteredCharSequence make(CharSequence source, char[] sub, int substart, int subend):创建一个变化的CharSequence,其文本(可能是spans)来自于source,除了指定范围([substart, subend))处是sub的偏移量为0的镜像

    1
    2
    3
    4
    5
    6
    public static AlteredCharSequence make(CharSequence source, char[] sub, int substart, int subend) {
    if (source instanceof Spanned)
    return new AlteredSpanned(source, sub, substart, subend);
    else
    return new AlteredCharSequence(source, sub, substart, subend);
    }
  3. public char charAt(int off):获取指定位置处的字符,注意off和指定字符数组提供区间[start, end)的关系

    1
    2
    3
    4
    5
    6
    public char charAt(int off) {
    if (off >= mStart && off < mEnd) // 获取指定字符数组sub区间内的字符
    return mChars[off - mStart];
    else // 获取指定CharSequence的off位置处的字符
    return mSource.charAt(off);
    }
  4. public void getChars(int start, int end, char[] dest, int off):从mSource中拷贝[start, end)范围的内容到dest中,注意拷贝区间和原始变化区间[mStart, mEnd)的关系处理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public void getChars(int start, int end, char[] dest, int off) {
    TextUtils.getChars(mSource, start, end, dest, off); // 由mSource决定拷贝[start, end)位置处的字符到偏移量为off的dest中
    // 着重处理mChars内的拷贝:获取最大的start和最小的end,使拷贝区间尽量在[mStart, mEnd)内,便于拷贝mChars的内容到dest中
    start = Math.max(mStart, start);
    end = Math.min(mEnd, end);
    if (start > end)
    System.arraycopy(mChars, start - mStart, dest, off, end - start);
    }
  5. TextUtils.getChars(CharSequence s, int start, int end, char[] dest, int destoff):依次判断s是否为StringStringBufferStringBuilderGetChars的实例,若是,调用对应的getChars()方法即可;若不是,将[start, end)位置处的字符拷贝到偏移量为destoffdest

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public static void getChars(CharSequence s, int start, int end, char[] dest, int destoff) {
    Class<? extends CharSequence> c = s.getClass();
    if (c == String.class)
    ((String) s).getChars(start, end, dest, destoff);
    else if (c == StringBuffer.class)
    ((StringBuffer) s).getChars(start, end, dest, destoff);
    else if (c == StringBuilder.class)
    ((StringBuilder) s).getChars(start, end, dest, destoff);
    else if (s instanceof GetChars)
    ((GetChars) s).getChars(start, end, dest, destoff);
    else {
    for (int i = start; i < end; i++)
    dest[destoff++] = s.charAt(i);
    }
    }

AlteredCharSequence.AlteredSpanned

定义在AlteredCharSequence中,Spanned的实现类,在AlteredCharSequence的基础上附加了Spanned的相关功能

Spanned系列

Spanned

  1. 描述
    • 用于让标记对象绑定到文本的某范围的文本的接口;并不是所有的类都有可变的标记或文本
  2. 具体方法
Method Description
T[] getSpans(int start, int end, Class type) 返回一个绑定指定类型的CharSequence或其子类的切片的标记对象数组;也可直接指定Object.class,不管任何类型
int getSpanStart(Object tag) 返回指定标记对象绑定的文本范围的开始位置;若对象没有绑定,返回-1
int getSpanEnd(Object tag) 返回指定标记对象绑定的文本范围的结束位置;若对象没有绑定,返回-1
int getSpanFlags(Object tag) 返回当使用Spannable.setSpan绑定指定的标记对象时指定的flags,若指定的对象未被绑定,这里返回0
int nextSpanTransition(int start, int limit, Class type) 返回第一个大于type类型标记对象开始或结束处的给定的start值,否则如果没有开始或结束值比给定的start值大,但是小于给定的limit,则返回该limit;可直接指定nullObject.class,不管任何类型

SpannableStringInternal

  1. 描述
  2. 待补充

SpannedString

  1. 描述
    • 文本的内容和标记对象都是不可变的
  2. public CharSequence subSequence(int start, int end):根据给定的[start, end]范围获取SpannedString实例

    1
    2
    3
    public CharSequence subSequence(int start, int end) {
    return new SpannedString(this, start, end);
    }
  3. public static SpannedString valueOf(CharSequence source):根据给定的CharSequence类型获取SpannedString实例

    1
    2
    3
    4
    5
    6
    7
    public static SpannedString valueOf(CharSequence source) {
    if (source instanceof SpannedString) {
    return (SpannedString) source;
    } else {
    return new SpannedString(source);
    }
    }

Spannable

  1. 描述
    • 用于标记对象可以绑定和解绑的文本的接口;并不是所有的类都有可变的文本,如Editable
  2. 具体方法
Method Description
void setSpan(Object what, int start, int end, int flags) 绑定指定的标记对象到文本的[start, end]范围处,或若标记对象已绑定了,则移除对应范围内的标记对象
void removeSpan(Object what) 从指定标记对象绑定的文本范围内移除该标记对象;第一次移除从未绑定的标记对象总是可行的

Spannable.Factory

  1. 描述
    • 用于TextView创建Spannable实例
    • 可以通过继承该类实现除SpannableString的其它类
  2. 具体方法
Method Description
static Spannable.Factory getInstance() 返回标准的Spannable工厂实例
Spannable newSpannable(CharSequence source) 根据给定的CharSequence提供SpannableString实例;可以重写该方法提供其它的Spannable类型

SpannableString

  1. 描述
    • 文本的内容是不可变的,文本的标记对象是可以绑定和解绑的
  2. public CharSequence subSequence(int start, int end):根据给定的[start, end]范围获取SpannableString实例

    1
    2
    3
    public CharSequence subSequence(int start, int end) {
    return new SpannableString(this, start, end);
    }
  3. public static SpannableString valueOf(CharSequence source):根据给定的CharSequence类型获取SpannableString实例

    1
    2
    3
    4
    5
    6
    7
    public static SpannableString valueOf(CharSequence source) {
    if (source instanceof SpannableString) {
    return (SpannableString) source;
    } else {
    return new SpannableString(source);
    }
    }
  4. 注意:提供了公共的setSpan()removeSpan()方法用于绑定和解绑标记对象

Editable

  1. 描述
    • 文本的内容和标记对象均可变化,与String不可变的文本形成对比
  2. 具体方法
Method Description
Editable replace(int st, int en, CharSequence source, int start, int end) 用给定sourcestart... end范围内的文本拷贝来替换该Editable中指定st...en范围的文本。当目标片段为空时,该方法表示插入操作;或源片段为空时,该方法表示删除操作。在变化发送之前,使用setFilters(InputFilter[])方法设置的过滤器可以帮助修改source的文本
Editable replace(int st, int en, CharSequence text) 等同于replace(st, en, text, 0, text.length())
Editable insert(int where, CharSequence text, int start, int end) 等同于replace(where, where, text, start, end)
Editable insert(int where, CharSequence text) 等同于replace(where, where, text, 0, text.length())
Editable delete(int st, int en) 等同于replace(st, en, "", 0, 0)
Editable append(CharSequence text) 等同于replace(length(), length(), text, 0, text.length())
Editable append(CharSequence text, int start, int end) 等同于replace(length(), length(), text, start, end)
Editable append(char text) 等同于append(String.valueOf(text))
void clear() 等同于replace(0, length(), "", 0, 0),注意该方法只清除文本,并不是spans
void clearSpans() 移除该Editable的所有spans
void setFilters(InputFilter[] filters) 设置一系列无论何时该Editable的文本变化时会成功调用的过滤器,每个过滤器可以限制或变换被插入的文本
InputFilter[] getFilters() 返回当前应用于该Editable的过滤器数组

Editable.Factory

  1. 描述
    • 用于TextView创建Editable实例
    • 可以通过继承该类实现除SpannableStringBuilder的其它类
  2. 具体方法
Method Description
static Editable.Factory getInstance() 返回标准的Editable实例
Editable newEditable(CharSequence source) 根据给定的CharSequence创建SpannableStringBuilder实例

GraphicsOperations

  1. 描述
    • 如果CharSequence能够做快速的绘制、测量、宽度计算,可以实现该接口
    • 其方法和CanvasPaint的方法类似

SpannableStringBuilder

  1. 描述
    • 文本的内容和标记对象都是可变的
  2. 待补充

String系列

String

  1. 描述
    • Java程序中所有字符串字面量,如“abc”作为String类的实例实现
    • 字符串是常量,创建后不能被修改
    • String包含有比较、搜索、提取子字符串、转换为大写或小写的字符串拷贝等方法
    • 支持字符串拼接(+)操作,方便其它对象转换为字符串;通过StringBuilderStringBuffer类和它们的append()方法实现字符串拼接;通过对象的toString()(由Object定义,其子类重写)方法实现转换
    • 传递null参数给String的构造函数或方法会抛出NullPointerException
    • String代表了增补的字符由代理对来表示的UTF-16格式的字符串,指数值引用了char的代码单位,所以在一个字符串中一个增补的字符使用了两个位置
    • String提供了处理Unicode代码点(如character类型)的方法,除了处理Unicode代码单元(如char类型值)

AbstractStringBuilder

  1. 描述
    • 可变的字符序列
    • StringBuilderStringBuffer类的抽象类
    • 通过某些调用方法可以修改序列的长度和内容
    • 传递null参数给构造函数或方法会抛出NullPointerException
  2. public void ensureCapacity(int minimumCapacity):确保容量至少等于提供的最小值。如果当前容量小于提供的最小值,一个新的内部数组会使用新的容量进行分配,其中新的容量是提供的最小值和当前容量的2倍再加2的值中的更大的一个

    1
    2
    3
    4
    public void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > 0) // 只有在提供参数大于0时才可实现容量扩大操作
    ensureCapacityInternal(minimumCapacity);
    }
  3. private void ensureCapacityInternal(int minimumCapacity):比较提供的最小容量和内部数组的长度,若大于0,根据提供的最小容量扩大内部的容量,否则什么也不做

    1
    2
    3
    4
    5
    private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) // 提供参数大于内部数组长度时才可实现容量扩大操作
    expandCapacity(minimumCapacity);
    }
  4. void expandCapacity(int minimumCapacity):实现容量扩大,并完成字符串的拷贝。注意当计算并比较后的最大容量小于0,也就是溢出,并且提供的最小容量值也小于0时,会抛出内存溢出异常

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
    if (newCapacity - minimumCapacity < 0) // 在当前容量基础上扩大后的容量值仍小于提供的最小容量值
    newCapacity = minimumCapacity;
    if (newCapacity < 0) { // 经比较后的新容量值溢出时
    // 若提供的最小容量值小于0,会直接抛出内存溢出异常
    if (minimumCapacity < 0) // overflow
    throw new OutOfMemoryError();
    // 否则设置新容量为最大整型值
    newCapacity = Integer.MAX_VALUE;
    }
    // 拷贝内部数组[0,Math.min(count, newCapacity))区间的内容
    value = Arrays.copyOf(value, newCapacity);
    }
  5. public void setLength(int newLength):设置字符序列的长度为提供的参数。若提供的长度小于当前的长度,该字符序列的长度变为提供的长度;若提供的长度大于当前的长度,追加额外的空字符(‘\0’)以便该字符序列的长度变为提供的长度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public void setLength(int newLength) {
    if (newLength < 0) // 提供的长度不准小于0
    throw new StringIndexOutOfBoundsException(newLength);
    ensureCapacityInternal(newLength); // 完成原有内部容量的扩大操作
    // 若内部内容长度小于提供的参数时,填充‘\0‘到内部数组的[count, newLength)区间处
    if (count < newLength) {
    Arrays.fill(value, count, newLength, '\0');
    }
    // 设置该字符序列的内容长度为提供的长度
    count = newLength;
    }
  6. public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):拷贝字符序列[srcBegin, srcEnd)位置处的内容到提供的dst数组中的偏移量destBegin处。注意拷贝之前对提供参数所进行的严格判断(提供指数超过数组界线异常问题)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
    {
    if (srcBegin < 0) // 拷贝的起始位置不能小于0
    throw new StringIndexOutOfBoundsException(srcBegin);
    if ((srcEnd < 0) || (srcEnd > count)) // 拷贝的结束位置不能小于0 或者 拷贝的结束为止不能大于内部内容长度
    throw new StringIndexOutOfBoundsException(srcEnd);
    if (srcBegin > srcEnd) // 拷贝的起始位置不能大于结束位置
    throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
    // 拷贝内部数组[srcBegin, srcEnd)区间处的内容到数组dst的[dstBegin, dstBegin+srcBegin-srcEnd)区间处
    System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }
  7. public AbstractStringBuilder append(String str):追加提供的字符串到该字符序列。若提供的strnull,追加“null”内容。注意追加内容后会根据提供内容的长度来增加该字符序列的长度,所以需要完成相应的容量扩大和内容长度设置操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public AbstractStringBuilder append(String str) {
    if (str == null) // 追加“null”内容
    return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len); // 完成原有内部容量的扩大操作
    str.getChars(0, len, value, count); // 拷贝str内容到内部数组的[count, count+len)区间处
    count += len; // 在原有内容长度基础上增加提供内容的长度
    return this;
    }
  8. private AbstractStringBuilder appendNull():完成“null”内容的追加操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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;
    }
  9. public AbstractStringBuilder delete(int start, int end):移除该字符序列[start, end)位置处的内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public AbstractStringBuilder delete(int start, int end) {
    if (start < 0) // 起始位置不能小于0
    throw new StringIndexOutOfBoundsException(start);
    if (end > count) // 保证结束位置的有效性(比较提供的结束位置和内部内容的长度)
    end = count;
    if (start > end) // 起始位置不能大于结束位置
    throw new StringIndexOutOfBoundsException();
    int len = end - start;
    if (len > 0) { // 移除合理的区间[start, end)处的内容,注意内部内容长度的设置操作(减少了len的长度)
    System.arraycopy(value, start+len, value, start, count-end);
    count -= len;
    }
    return this;
    }
  10. public AbstractStringBuilder replace(int start, int end, String str):使用提供的字符串str来替换该字符序列的给定区间[start, end)处的字符

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public AbstractStringBuilder replace(int start, int end, String str) {
    if (start < 0) // 起始位置不能小于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();
    int newCount = count + len - (end - start);
    ensureCapacityInternal(newCount); // 变换原有内部容量操作
    // 直接拷贝内部数组[end, count)区间处的内容到扩大后的内部容量的[start+len, newCount)区间处
    System.arraycopy(value, end, value, start + len, count - end);
    str.getChars(value, start); // 直接拷贝str到[start, start+len)区间处
    count = newCount;
    return this;
    }
  11. public String substring(int start, int end):创建提供[start, end)区间参数处的字符序列的字符串

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public String substring(int start, int end) {
    if (start < 0) // 起始位置不能小于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); // 创建由[start, end)区间处的字符序列组成的字符串
    }
  12. public AbstractStringBuilder insert(int index, char[] str, int offset, int len):将提供的数组str偏移量offset开始len长度的内容插入到该字符序列的index位置处

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public AbstractStringBuilder insert(int index, char[] str, int offset, int len)
    {
    if ((index < 0) || (index > length())) // 插入位置不能小于0 或者 大于内部容量
    throw new StringIndexOutOfBoundsException(index);
    // 拷贝的偏移量不能小于0 或者 拷贝内容的长度不能小于0 或者 拷贝的偏移量不能大于所拷贝内容的长度与欲拷贝的长度差值
    if ((offset < 0) || (len < 0) || (offset > str.length - len))
    throw new StringIndexOutOfBoundsException(
    "offset " + offset + ", len " + len + ", str.length "
    + str.length);
    ensureCapacityInternal(count + len); // 完成扩大内部容量操作
    // 拷贝内部数组[index, count)区间处的内容到[index+len, count+len)区间处
    System.arraycopy(value, index, value, index + len, count - index);
    // 拷贝数组str[offset, len)区间处的内容到内部数组[index, index+len)区间处
    System.arraycopy(str, offset, value, index, len);
    count += len; // 在原有内部内容长度基础上增加插入内容长度
    return this;
    }
  13. public AbstractStringBuilder insert(int offset, String str):将提供的字符串str插入到该字符序列的offset位置处

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public AbstractStringBuilder insert(int offset, String str) {
    if ((offset < 0) || (offset > length())) // 偏移量不能小于0 或者 不能大于内部容量
    throw new StringIndexOutOfBoundsException(offset);
    if (str == null) // 若提供参数为null,插入“null”字符串
    str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len); // 完成扩大内部容量操作
    // 拷贝内部数组[offset, count)区间处的内容到[offset+len, count+len)区间处
    System.arraycopy(value, offset, value, offset + len, count - offset);
    str.getChars(value, offset); // 拷贝提供的字符串到[offset, offset+len)区间处
    count += len;
    return this;
    }
  14. public AbstractStringBuilder reverse()待补充

StringBuilder

  1. 描述
    • 可变的字符序列
    • 兼容StringBuffer,但不能保证同步
    • 该类被设计用于字符串缓存在单线程使用时用于StringBuffer的混乱信息替换
    • 该类相对于StringBuffer被推荐使用,因为其大多情况下更快
    • 重载appendinsert等方法,支持任意类型数据
    • StringBulder实例在多线程场景中不安全
  2. public String toString():重写toString()方法
    1
    2
    3
    4
    5
    @Override
    public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
    }

StringBuffer

  1. 描述
    • 线程安全、可变的字符序列
    • 可通过某些方法调用实现字符序列长度和内容的修改
    • 重载appendinsert等方法,支持任意类型数据
  2. toStringCachetransient变量,用于缓存toString()方法拷贝的该类的内部数组,当被修改时会被清空

    1
    2
    3
    4
    5
    /**
    * A cache of the last value returned by toString. Cleared
    * whenever the StringBuffer is modified.
    */
    private transient char[] toStringCache;
  3. public synchronized String toString():重写toString()方法

    1
    2
    3
    4
    5
    6
    7
    @Override
    public synchronized String toString() {
    if (toStringCache == null) {
    toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
    }

参考方案

  1. CharSequence API
  2. Java - Serializable
  3. Serializable in Java
  4. Java Comparable Interface in Five Minutes
  5. Java Comparable interface
  6. Java 解惑:Comparable 和 Comparator 的区别
  7. Android Spannable text view to change color, size, style and adding click event for particular word
  8. 其实你不懂:Android之Spanned flag