JDK源码之AbstractStringBuilder类分析
一 概述
二 实现接口
AbstractStringBuilder实现了两个接口:
- Appendable
- 概述:
Appendable的实现类的对象可以附加字符序列和值.
要追加的字符应该是Unicode字符表示中描述的有效Unicode字符。注意,补充字符可能由多个16位字符值组成。
对于多线程访问不一定是安全的。线程安全是扩展和实现这个接口的类的职责。
IO流操作的写类基本都实现了这个接口,比如BufferedWriter, CharArrayWriter, CharBuffer, FileWriter等,还有StringBuffer和StringBuild也实现了这个接口 - 接口定义的方法:
- 概述:
/**
* 添加CharSequence序列到当前对象,并返回当前对象
*/
Appendable append(CharSequence csq) throws IOException;
/**
* 添加CharSequence序列参数的子序列,按照参数进行分割,到当前对象
*/
Appendable append(CharSequence csq, int start, int end) throws IOException;
/**
* 添加char值到当前对象
*/
Appendable append(char c) throws IOException;
CharSequence
这个接口就不多说了,表示char 值的一个可读序列(有序集合),
三 源码解析
1 属性
// 表示AbstractStringBuilder的值,可变的byte数组,jdk9之前是char数组
byte[] value;
// coder编码值,jdk9之后添加的编码标识,和String的编码coder是一样的
byte coder;
// 当前字符串已经使用的byte数组中的长度,增删改查的同时需要维护这个属性值
int count;
//空byte数组,用于无参构造器初始化,jdk9之后新增的
private static final byte[] EMPTYVALUE = new byte[0];
// 能创建数组长度的最大值
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
2 构造器
/**
* 无参构造器,vlaue默认赋值为一个长度为0的byte数组
*/
AbstractStringBuilder() {
value = EMPTYVALUE;
}
/**
* 根据参数创建指定长度的byte数组
*/
AbstractStringBuilder(int capacity) {
// 根据是否压缩标识创建单字节或者双字节存储
if (COMPACT_STRINGS) {
value = new byte[capacity];
coder = LATIN1;
} else {
value = StringUTF16.newBytesFor(capacity);//将capacity << 1 ,即创建capacity乘以2的大小byte数组
coder = UTF16;
}
}
3 基本api
//jdk11新增方法,比较大小
int compareTo(AbstractStringBuilder another) {
if (this == another) {
return 0;
}
byte val1[] = value;
byte val2[] = another.value;
int count1 = this.count;
int count2 = another.count;
if (coder == another.coder) {
return isLatin1() ? StringLatin1.compareTo(val1, val2, count1, count2)
: StringUTF16.compareTo(val1, val2, count1, count2);
}
return isLatin1() ? StringLatin1.compareToUTF16(val1, val2, count1, count2)
: StringUTF16.compareToLatin1(val1, val2, count1, count2);
}
//返回当前字符串实际的长度
@Override
public int length() {
return count;
}
//返回当前字符所占用byte数组的长度, >= length()
public int capacity() {
return value.length >> coder;
}
//确保当前value的数组长度至少等于指定的参数
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0) {
ensureCapacityInternal(minimumCapacity);
}
}
private void ensureCapacityInternal(int minimumCapacity) {
// 防止append的时候数组越界
int oldCapacity = value.length >> coder;
if (minimumCapacity - oldCapacity > 0) { //参数 > 当前byte数组长度
// 创建新长度大小的byte数组,并将value值进行copy,重新赋值给当前value
value = Arrays.copyOf(value,
newCapacity(minimumCapacity) << coder);
}
}
/**
* 判断给定参数是否溢出或者小于0,并返回合理的数组长度
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
int newCapacity = (oldCapacity << 1) + 2;
//每次扩容,最少扩大原来的2倍+2
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
// 验证扩容值是否溢出
return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
//越界检查.是否超过最大值
private int hugeCapacity(int minCapacity) {
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
int UNSAFE_BOUND = Integer.MAX_VALUE >> coder;
if (UNSAFE_BOUND - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > SAFE_BOUND)
? minCapacity : SAFE_BOUND;
}
//如果编码是Latin,则byte数组扩容为原来两倍,并将原有的值按双字节存储,编码改为UTF16
private void inflate() {
if (!isLatin1()) {
return;
}
byte[] buf = StringUTF16.newBytesFor(value.length);
StringLatin1.inflate(value, 0, buf, 0, count);
this.value = buf;
this.coder = UTF16;
}
//如果value数组的容量有多余的,那么就把多余的全部都释放掉
public void trimToSize() {
int length = count << coder; //实际使用了的长度
if (length < value.length) { // byte数组长度
value = Arrays.copyOf(value, length);
}
}
/**
* 强制增大实际长度count的大小,容量如果不够就用 expandCapacity()扩大;
* 将扩大的部分全部用’\0’(ASCII码中的null)来初始化
*/
public void setLength(int newLength) {
if (newLength < 0) {
throw new StringIndexOutOfBoundsException(newLength);
}
ensureCapacityInternal(newLength);
if (count < newLength) {
if (isLatin1()) {
//使用null填充
StringLatin1.fillNull(value, count, newLength);
} else {
StringUTF16.fillNull(value, count, newLength);
}
}
count = newLength;
}
// 抽象方法,需要子类自己实现
@Override
public abstract String toString();
4 增(append)
/**
* 添加Object,实际是把对象转为String,调用添加String方法
*/
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
/**
* 添加String
*/
public AbstractStringBuilder append(String str) {
if (str == null) {
return appendNull();
}
int len = str.length();
//对 byte数组扩容,确保长度大于 count+len
ensureCapacityInternal(count + len);
//讲str追加到byte数组中
putStringAt(count, str);
count += len; //修改实际占用长度
return this;
}
//添加 StringBuffer
public AbstractStringBuilder append(StringBuffer sb) {
return this.append((AbstractStringBuilder)sb);
}
/**
* jdk1.8新加的方法,逻辑跟添加String是一样的
*/
AbstractStringBuilder append(AbstractStringBuilder asb) {
if (asb == null) {
return appendNull();
}
int len = asb.length();
ensureCapacityInternal(count + len);
if (getCoder() != asb.getCoder()) {
inflate();
}
asb.getBytes(value, count, coder);
count += len;
return this;
}
// 添加 CharSequence,实现Appendable接口的方法
@Override
public AbstractStringBuilder append(CharSequence s) {
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());
}
// 添加字符串 "null"
private AbstractStringBuilder appendNull() {
ensureCapacityInternal(count + 4);
int count = this.count;
byte[] val = this.value;
if (isLatin1()) {
val[count++] = 'n';
val[count++] = 'u';
val[count++] = 'l';
val[count++] = 'l';
} else {
count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
}
this.count = count;
return this;
}
//指定位置添加 s
@Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null) {
s = "null";
}
checkRange(start, end, s.length());
int len = end - start;
ensureCapacityInternal(count + len);
appendChars(s, start, end);
return this;
}
// 添加插入数组
public AbstractStringBuilder append(char[] str) {
int len = str.length;
ensureCapacityInternal(count + len);
appendChars(str, 0, len);
return this;
}
/**
* 添加插入数组, 指定开始位置和添加的长度
*/
public AbstractStringBuilder append(char str[], int offset, int len) {
int end = offset + len;
checkRange(offset, end, str.length);
ensureCapacityInternal(count + len);
appendChars(str, offset, end);
return this;
}
// 添加 'true' 或者 'false'
public AbstractStringBuilder append(boolean b) {
ensureCapacityInternal(count + (b ? 4 : 5));
int count = this.count;
byte[] val = this.value;
if (isLatin1()) {
if (b) {
val[count++] = 't';
val[count++] = 'r';
val[count++] = 'u';
val[count++] = 'e';
} else {
val[count++] = 'f';
val[count++] = 'a';
val[count++] = 'l';
val[count++] = 's';
val[count++] = 'e';
}
} else {
if (b) {
count = StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e');
} else {
count = StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e');
}
}
this.count = count;
return this;
}
//添加unicode代码点
public AbstractStringBuilder appendCodePoint(int codePoint) {
if (Character.isBmpCodePoint(codePoint)) {
return append((char)codePoint);
}
return append(Character.toChars(codePoint));
}
// 添加 char
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
if (isLatin1() && StringLatin1.canEncode(c)) {
value[count++] = (byte)c;
} else {
if (isLatin1()) {
inflate();
}
StringUTF16.putCharSB(value, count++, c);
}
return this;
}
// 添加 int,以下都是添加number
public AbstractStringBuilder append(int i) {
int count = this.count;
int spaceNeeded = count + Integer.stringSize(i);
ensureCapacityInternal(spaceNeeded);
if (isLatin1()) {
Integer.getChars(i, spaceNeeded, value);
} else {
StringUTF16.getChars(i, count, spaceNeeded, value);
}
this.count = spaceNeeded;
return this;
}
public AbstractStringBuilder append(long l) {
int count = this.count;
int spaceNeeded = count + Long.stringSize(l);
ensureCapacityInternal(spaceNeeded);
if (isLatin1()) {
Long.getChars(l, spaceNeeded, value);
} else {
StringUTF16.getChars(l, count, spaceNeeded, value);
}
this.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;
}
/**
* 在 index位置插入 char数组的一部分,这部分从是[ offset,offset + len )
*/
public AbstractStringBuilder insert(int index, char[] str, int offset,
int len)
{
checkOffset(index, count);
checkRangeSIOOBE(offset, offset + len, str.length);
ensureCapacityInternal(count + len);
shift(index, len);
count += len;
putCharsAt(index, str, offset, offset + len);
return this;
}
/**
* 在 offset位置,插入 obj,其他像int,boolean 都是类似的用String.valueOf转然后调用插入String方法
*/
public AbstractStringBuilder insert(int offset, Object obj) {
return insert(offset, String.valueOf(obj));
}
public AbstractStringBuilder insert(int offset, String str) {
checkOffset(offset, count);
if (str == null) {
str = "null";
}
int len = str.length();
ensureCapacityInternal(count + len);
shift(offset, len);
count += len;
putStringAt(offset, str);
return this;
}
5 删
/**
* 删除指定位置的字符
*/
public AbstractStringBuilder delete(int start, int end) {
int count = this.count;
if (end > count) {
end = count;
}
checkRangeSIOOBE(start, end, count);
int len = end - start;
if (len > 0) {
shift(end, -len); //调用System.arraycopy 方法
this.count = count - len;
}
return this;
}
/**
* 删除指定位置的字符
*/
public AbstractStringBuilder deleteCharAt(int index) {
checkIndex(index, count);
shift(index + 1, -1); //删除 index index+1 位置的字符
count--;
return this;
}
// 将value从offset开始复制 count-offset个值,从 offset+n 开始重新赋值给value, 即删减 n 个字符
private void shift(int offset, int n) {
System.arraycopy(value, offset << coder,
value, (offset + n) << coder, (count - offset) << coder);
}
6 改
/**
* 用字符串str替换掉value[]数组的[start,end)部分
*/
public AbstractStringBuilder replace(int start, int end, String str) {
int count = this.count;
if (end > count) {
end = count;
}
checkRangeSIOOBE(start, end, count);
int len = str.length();
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount);//扩容
shift(end, newCount - count);// 从指定end处开始,删除或者增加 newCount - count个值
this.count = newCount;
putStringAt(start, str); //从start开始添加字符
return this;
}
//截取子字符串
public String substring(int start) {
return substring(start, count);
}
public String substring(int start, int end) {
checkRangeSIOOBE(start, end, count);
if (isLatin1()) {
return StringLatin1.newString(value, start, end - start);
}
return StringUTF16.newString(value, start, end - start);
}
/**
* 在指定index位置设置 char值
*/
public void setCharAt(int index, char ch) {
checkIndex(index, count);
if (isLatin1() && StringLatin1.canEncode(ch)) {
value[index] = (byte)ch;
} else {
if (isLatin1()) {
inflate();
}
StringUTF16.putCharSB(value, index, ch);
}
}
/**
* 将value给倒序存放(注意改变的就是本value,而不是创建了一个新的AbstractStringBuilder然后value为倒序)
*/
public AbstractStringBuilder reverse() {
byte[] val = this.value;
int count = this.count;
int coder = this.coder;
int n = count - 1;
if (COMPACT_STRINGS && coder == LATIN1) {
for (int j = (n-1) >> 1; j >= 0; j--) {
int k = n - j;
byte cj = val[j];
val[j] = val[k];
val[k] = cj;
}
} else {
StringUTF16.reverse(val, count);
}
return this;
}
7 查
/**
* 获取下标为index的char字符
*/
@Override
public char charAt(int index) {
checkIndex(index, count);
if (isLatin1()) {
return (char)(value[index] & 0xff);
}
return StringUTF16.charAt(value, index);
}
/**
* 获取index位置的unicode代码单位
*/
public int codePointAt(int index) {
int count = this.count;
byte[] value = this.value;
checkIndex(index, count);
if (isLatin1()) {
return value[index] & 0xff;
}
return StringUTF16.codePointAtSB(value, index, count);
}
/**
* 将value[]的 [srcBegin, srcEnd) 拷贝到 dst[]数组的desBegin开始处
*/
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
checkRangeSIOOBE(srcBegin, srcEnd, count); // compatible to old version
int n = srcEnd - srcBegin;
checkRange(dstBegin, dstBegin + n, dst.length);
if (isLatin1()) {
StringLatin1.getChars(value, srcBegin, srcEnd, dst, dstBegin);
} else {
StringUTF16.getChars(value, srcBegin, srcEnd, dst, dstBegin);
}
}
//在value[]中找字符串str,若能找到,返回第一个字符串的第一个字符的下标
public int indexOf(String str) {
return indexOf(str, 0);
}
//从fromIndex开始,在value[]中找字符串str,若能找到,返回第一个字符串的第一个字符的下标
public int indexOf(String str, int fromIndex) {
return String.indexOf(value, coder, count, str, fromIndex);
}
// 从后面往前找
public int lastIndexOf(String str) {
return lastIndexOf(str, count);
}
// 从后面往前找
public int lastIndexOf(String str, int fromIndex) {
return String.lastIndexOf(value, coder, count, str, fromIndex);
}
/**
* jdk9 新增方法,获取int流
*/
@Override
public IntStream chars() {
return StreamSupport.intStream(
() -> {
byte[] val = this.value;
int count = this.count;
byte coder = this.coder;
return coder == LATIN1
? new StringLatin1.CharsSpliterator(val, 0, count, 0)
: new StringUTF16.CharsSpliterator(val, 0, count, 0);
},
Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED,
false);
}
/**
* jdk9 新增方法,获取unicode代码点int 流
*/
@Override
public IntStream codePoints() {
return StreamSupport.intStream(
() -> {
byte[] val = this.value;
int count = this.count;
byte coder = this.coder;
return coder == LATIN1
? new StringLatin1.CharsSpliterator(val, 0, count, 0)
: new StringUTF16.CodePointsSpliterator(val, 0, count, 0);
},
Spliterator.ORDERED,
false);
}
四 总结
AbstractStringBuilder就是 可变 字符序列的一个纲领
它规定了可变字符序列应该有的行为
比如 添加字符/删除字符/更新字符/获取字符
因为可变,所以对于可变的支持,自然是必不可少的
另外,他作为String在很多方面的一个替代,必然也是提供了String的一些功能方法
否则与String API 变化巨大 也是毫无意义
因为毕竟本身就是为了描述字符序列
所以对于AbstractStringBuilder 只需要彻底理解了他作为 可变字符序列的标准接口即可
接口的两个实现StringBuffer和StringBuild大部分的功能也都是调用的父类方法!
JDK源码之AbstractStringBuilder类分析的更多相关文章
- JDK源码之Integer类分析
一 简介 Integer是int基本类型的包装类,同样继承了Number类,实现了Comparable接口,String类中的一些转化方法就使用了Integer类中的一些API,且fianl修饰不可继 ...
- JDK源码之Byte类分析
一 简介 byte,即字节,由8位的二进制组成.在Java中,byte类型的数据是8位带符号的二进制数,以二进制补码表示的整数 取值范围:默认值为0,最小值为-128(-2^7);最大值是127(2^ ...
- JDK源码之Boolean类分析
一 简介 boolean类型的封装类,将基本类型为boolean的值包装在一个对象中,实现序列化接口,和Comparable接口 额外提供了许多便捷方法,比较简单,直接贴代码分析 二 源码分析 //t ...
- JDK源码之Double类&Float类分析
一 概述 Double 类是基本类型double的包装类,fainl修饰,在对象中包装了一个基本类型double的值.Double继承了Number抽象类,具有了转化为基本double类型的功能. 此 ...
- JDK源码之String类解析
一 概述 String由final修饰,是不可变类,即String对象也是不可变对象.这意味着当修改一个String对象的内容时,JVM不会改变原来的对象,而是生成一个新的String对象 主要考虑以 ...
- [Android FrameWork 6.0源码学习] LayoutInflater 类分析
LayoutInflater是用来解析XML布局文件,然后生成对象的ViewTree的工具类.是这个工具类的存在,才能让我们写起Layout来那么省劲. 我们接下来进去刨析,看看里边的奥秘 //调用i ...
- jdk源码理解-String类
String类的理解 简记录一下对于jdk的学习,做一下记录,会持续补充,不断学习,加油 1.String的hash值的计算方法. hash值的计算方法多种多样,jdk中String的计算方法如下,比 ...
- JDK源码阅读--AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence /** * The value is used for ...
- jdk源码阅读-Object类
native 关键字 private static native void registerNatives(); static { registerNatives(); } public final ...
随机推荐
- 【python测试开发栈】—帮你总结Python os模块高频使用的方法
Python中的os模块是主要和系统操作相关的模块,在平时的工作中会经常用到,花时间整理了os模块的高频使用方法,同时整理出使用时需要注意的点.归纳来讲,os模块的方法可以分为:目录操作.文件操作.路 ...
- 金蝶handler中 collection 代码片段理解
1,AtsOverTimeBillBatchEditHandler中collection的理解 SelectorItemCollection selectors = new SelectorItemC ...
- mysql主从之基于atlas读写分离
一 mysql读写分离的概念 写在主库,主库一般只有一个,读可以分配在多个从库上,如果写压力不大的话,也能把读分配到主库上. 实现是基于atlas实现的,atlas是数据库的中间件,程序只需要连接at ...
- Java高级特性——流
以上就是这段时间学习完流的知识以后我的总结,.mmap文件可以去我的github上获取:https://github.com/xiaozhengyu/StudyNotes.git
- 「算法竞赛进阶指南」0x01 位运算 知识笔记
二进制是计算机的根本! 你了解她它吗? int lowbit(int x) { return x&(-x);//x&(~x+1),~x=-1-x; } int __builtin_ct ...
- 小小知识点(二十六)关于5G发展的28个核心问题,来自华为内部的深度解读
本文来自微信公众号“腾讯深网”(ID:qqshenwang),作者 马关夏.36氪经授权转载. 一.5G先进性与行业应用 1.5G到底是什么?和4G比有什么不一样? 从国际电信联盟(ITU)的定义来看 ...
- U盘中了蠕虫病毒,文件夹都变成exe了,怎么办?
昨天做实验,用U盘拷了实验室的文件,然后就中了病毒了(无奈),U盘里的文件全都变成了exe.有点慌张,我的U盘里存了很多课程资料.然而,我懒得下载杀毒软件.参考这位博主的做法,我成功的找回了我隐藏的文 ...
- 【JDBC】Java程序的数据库初体验
JDBC是什么 JDBC是一种能够用来执行SQL语句的Java API[接口]. 它是Java提供的一种规范,让各大数据库厂商遵循此规范完成自己的数据库连接驱动[实现接口]. JDBC的入门程序(这里 ...
- 【转】面向GC的Java编程
Java程序员在编码过程中通常不需要考虑内存问题,JVM经过高度优化的GC机制大部分情况下都能够很好地处理堆(Heap)的清理问题.以至于许多Java程序员认为,我只需要关心何时创建对象,而回收对象, ...
- C#登出系统并清除Cookie
1.前端页面代码: 前端页面代码主要显示退出系统或者网站的可视化按钮代码,代码如下:(请忽略项目关键字:CPU) <ul class="nav navbar-nav navbar-ri ...