StringBuilder&StringBuffer 源码阅读
StringBuilder 和 StringBuffer
StringBuilder 和 StringBuffer 都继承了 AbstractStringBuilder 类,所有实际的字符操作都在父类实现,
主要的区别是 StringBuilder 只是简单的调用父类方法,而 StringBuffer 的写操作都添加了 synchronized 关键字。
StringBuffer 是线程安全的,而 StringBuilder 不是线程安全的。
AbstractStringBuilder
- 属性说明
/**
* 可变的字符序列
*
* @author Michael McCloskey
* @author Martin Buchholz
* @author Ulf Zibis
* @since 1.5
*/
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* 用于字符存储的字节数组
*/
byte[] value;
/**
* 编码器
*/
byte coder;
/**
* 字符总数
*/
int count;
- 追加字符
/**
* 往可变字符序列中追加 boolean 值
*
* @param b 一个 boolean 值
*/
public AbstractStringBuilder append(boolean b) {
// 尝试进行扩容
ensureCapacityInternal(count + (b ? 4 : 5));
// 读取当前字符数到局部变量表
int count = this.count;
// 读取字节数组到局部变量表
final byte[] val = value;
// 1)如果是 LATIN1 编码
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';
}
// 2)如果是 UTF16 编码
} 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;
}
/**
* 往可变字符序列中追加单个字符
*
* @param c 单个字符
*/
@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 值
*
* @param i 一个 int 值
*/
public AbstractStringBuilder append(int i) {
final int count = this.count;
final 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;
}
/**
* 往可变字符序列中追加 long 值
*
* @param l 一个 long 值
*/
public AbstractStringBuilder append(long l) {
final int count = this.count;
final 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;
}
/**
* 往可变字符序列中追加 float 值
*
* @param f 一个浮点值
*/
public AbstractStringBuilder append(float f) {
FloatingDecimal.appendTo(f,this);
return this;
}
/**
* 往可变字符序列中追加 double 值
*
* @param d 一个 double 值
*/
public AbstractStringBuilder append(double d) {
FloatingDecimal.appendTo(d,this);
return this;
}
/**
* 往可变字符序列中追加对象
*
* @param obj 一个对象
*/
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
/**
* 往可变字符序列中追加字符串
*
* @param str 一个字符串
*/
public AbstractStringBuilder append(String str) {
if (str == null) {
return appendNull();
}
final int len = str.length();
ensureCapacityInternal(count + len);
putStringAt(count, str);
count += len;
return this;
}
/**
* 往可变字符序列中追加字符数组
*
* @param str 字符数组
*/
public AbstractStringBuilder append(char[] str) {
final int len = str.length;
ensureCapacityInternal(count + len);
appendChars(str, 0, len);
return this;
}
/**
* 往可变字符序列中追加字符序列
*
* @param s 目标字符序列
*/
@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());
}
- 扩容过程
/**
* 尝试进行扩容
*/
private void ensureCapacityInternal(int minimumCapacity) {
// 读取旧容量 overflow-conscious code
final int oldCapacity = value.length >> coder;
// 所需最小容量 > 旧容量
if (minimumCapacity - oldCapacity > 0) {
// 扩容并拷贝源字节数组
value = Arrays.copyOf(value,
newCapacity(minimumCapacity) << coder);
}
}
/**
* 返回大于 minCapacity 的最小容量值
*
* @param minCapacity 期望的最小容量
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
final int oldCapacity = value.length >> coder;
// 双倍扩容 + 2
int newCapacity = (oldCapacity << 1) + 2;
// 扩容后新容量还是 < 期望最小容量,则使用期望最小容量
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
final int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
// 一般不会走 hugeCapacity
return newCapacity <= 0 || SAFE_BOUND - newCapacity < 0 ? hugeCapacity(minCapacity) : newCapacity;
}
private int hugeCapacity(int minCapacity) {
final int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
final int UNSAFE_BOUND = Integer.MAX_VALUE >> coder;
if (UNSAFE_BOUND - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return minCapacity > SAFE_BOUND
? minCapacity : SAFE_BOUND;
}
- 插入字符
/**
* 在目标索引处插入 boolean 值
*
* @param offset 目标索引
* @param b 一个 boolean 值
*/
public AbstractStringBuilder insert(int offset, boolean b) {
return insert(offset, String.valueOf(b));
}
/**
* 在目标索引 offset 处插入字符串。
*
* @param offset 目标索引
* @param str 字符串
*/
public AbstractStringBuilder insert(int offset, String str) {
// 校验索引的合法性
checkOffset(offset, count);
// 目标字符为 null,则插入 'null'
if (str == null) {
str = "null";
}
// 计算目标字符长度
final int len = str.length();
// 尝试扩容
ensureCapacityInternal(count + len);
// 目标索引处及其之后的字符数组集体右移 len 个位置
shift(offset, len);
count += len;
// 插入目标字符串到指定索引 offset 处
putStringAt(offset, str);
return this;
}
/**
* 通过数组拷贝完成子数组迁移
*
* @param offset 目标索引
* @param n
*/
private void shift(int offset, int n) {
System.arraycopy(value, offset << coder,
value, offset + n << coder, count - offset << coder);
}
- 删除字符
/**
* 删除目标索引 start 和 end 之间的所有字符,包括起始不包括结束
*
* @param start 起始索引,包含
* @param end 结束索引,不包含
*/
public AbstractStringBuilder delete(int start, int end) {
// 从堆内存加载数据到栈局部变量表
final int count = this.count;
if (end > count) {
end = count;
}
checkRangeSIOOBE(start, end, count);
final int len = end - start;
if (len > 0) {
// 从 start 索引处开始的子字符数组集体左移 len 个位置
shift(end, -len);
this.count = count - len;
}
return this;
}
/**
* 删除指定索引 index 处的单个字符
*
* @param index 待移除字符的索引
*/
public AbstractStringBuilder deleteCharAt(int index) {
checkIndex(index, count);
shift(index + 1, -1);
count--;
return this;
}
- 截取子字符串
/**
* 截取起始索引 start 到结束索引 end 之间的子字符串
*
* @param start 起始索引,包括
* @param end 结束索引,不包括
*/
@Override
public CharSequence subSequence(int start, int end) {
return substring(start, end);
}
/**
* 截取起始索引 start 到结束索引 end 之间的子字符串
*
* @param start 起始索引,包括
* @param end 结束索引,不包括
*/
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);
}
/**
* 从起始索引 start 开始,截取剩余的子字符串
*
* @param start 起始索引,包括
*/
public String substring(int start) {
return substring(start, count);
}
StringBuilder&StringBuffer 源码阅读的更多相关文章
- [面试]StringBuilder StringBuffer源码粘贴(并非源码分析, 请绕道)
StringBuilder StringBuffer 源码 这里只是我个人笔记, 并没有在这篇文章里做任何技术分享, 请同学们绕道- -.如果需要我会后期补上的..... 本来是想分析源码来着, 但是 ...
- JDK部分源码阅读与理解
本文为博主原创,允许转载,但请声明原文地址:http://www.coselding.cn/article/2016/05/31/JDK部分源码阅读与理解/ 不喜欢重复造轮子,不喜欢贴各种东西.JDK ...
- 源码阅读系列:EventBus
title: 源码阅读系列:EventBus date: 2016-12-22 16:16:47 tags: 源码阅读 --- EventBus 是人们在日常开发中经常会用到的开源库,即使是不直接用的 ...
- EventBus源码解析 源码阅读记录
EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...
- 如何阅读Java源码 阅读java的真实体会
刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比 ...
- [收藏] Java源码阅读的真实体会
收藏自http://www.iteye.com/topic/1113732 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我 ...
- Rpc框架dubbo-client(v2.6.3) 源码阅读(二)
接上一篇 dubbo-server 之后,再来看一下 dubbo-client 是如何工作的. dubbo提供者服务示例, 其结构是这样的!dubbo://192.168.11.6:20880/com ...
- Java源码阅读的真实体会(一种学习思路)
Java源码阅读的真实体会(一种学习思路) 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈 ...
- Java源码阅读的真实体会(一种学习思路)【转】
Java源码阅读的真实体会(一种学习思路) 刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+ ...
随机推荐
- Hyperledger Fabric(1)基础架构
前言 在区块链的家谱里,第一代区块链系统是以比特币为代表的公链,主要实现的是数字货币的功能:第二代区块链系统是以以太坊平台为代表的公链,创造性的实现了智能合约.而第三代区块链系统,则是HyperLed ...
- Navicat连接Mysql11.1.13出现1251错误
打开Navicat软件,单击左上角[连接]按钮,选择mysql,弹出新建连接,输入相关信息,单击[连接测试],报1251的错误,如下图所示: 根因分析: mysql8 之前的版本中加密规则是mysql ...
- Delphi Label组件
- 02:Java基础语法(一)
Java基础语法 Java的关键字及保留字 关键字(Keyword) 关键字的定义和特点定义:被Java语言赋予了特殊含义的单词特点:关键字中所有字母都为小写注意事项:1)true.false.nul ...
- python-迭代器与生成器1
python-迭代器与生成器1 迭代器与生成器列表的定义列表生成式:作用使代码更加简洁通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元 ...
- C语言字符串操作小结
1)字符串操作strcpy(p, p1) 复制字符串strncpy(p, p1, n) 复制指定长度字符串strcat(p, p1) 附加字符串strncat(p, p1, n) 附加指定长度字符串s ...
- linux的一些运维操作基本知识
1 ~/.bashrc 这个可以认为是linux系统的启动项,每次启动的时候都会运行一些这里边的命令: 常见的有: alias rm='rm -i'//修改某些指令: export LD_LIBRAR ...
- 小程序UI设计(6)-布局分解-九宫格
今天我们来个庖丁解牛.对于一个完整的组合组件,看看通过工具是如何轻松完成的.首先看看九宫格完整的样子. 结构树是这样的.在结构树中,我们可以看到WViewColumn下面有九个WViewRow.WVi ...
- 浅析Java web程序之客户端和服务器端交互原理
原文链接: https://www.iteye.com/topic/470019 1. 协议 a. TCP/IP整体构架概述 TCP/IP协议并不完全符合OSI的七层参考模型.传统的开放式系统互连参考 ...
- jquery $(".classc",$(".classp"))的含义
jquery中有一种选择器的写法为:$(".classc",$(".classp")),注意,是$()中又嵌套了一个$(),这种写法的作用类似于$(" ...