JDK源码阅读(3):AbstractStringBuilder、StringBuffer、StringBuilder类阅读笔记
AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence{
...
}
1. inflate方法
inflate()方法可以将当前的Latin1编码的字符串膨胀到16位,即UTF16编码(Latin1编码为8位)
/**
* If the coder is "isLatin1", this inflates the internal 8-bit storage
* to 16-bit <hi=0, low> pair storage.
*/
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;
}
2. ensureCapacity方法
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0) {
ensureCapacityInternal(minimumCapacity);
}
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
if (minimumCapacity - oldCapacity > 0) {
// 拷贝过去
value = Arrays.copyOf(value, newCapacity(minimumCapacity) << coder);
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
int newCapacity = (oldCapacity << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
ensureCapacity(miniCapacity)方法保证当前容器的大小不小于miniCapacity,如果小于的话就要进行扩容处理。扩容成下面两者中的较大值。
- miniCapacity
- 2*oldCapacity
3. setCharAt方法
setCharAt()方法可以将index处的字符设为ch
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);
}
}
4. append方法
append()方法根据参数类型不同,在字符串后面追加。
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());
}
值得一提的是这个appendNull()方法,当我们在试图append一个空对象时,它居然选择在builder串后面加上一个“null”,看下面的示例。
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("a");
String s = null;
stringBuilder.append(s);
System.out.println(stringBuilder.toString());
System.out.println(stringBuilder.toString().length());
}
输出结果居然是
anull
5
也就是说,当append空对象时,会append一个“null”字符串。
另外,当我们尝试append一个boolean对象时,会append一个“true”串或者“false”串。
5. delete方法
delete方法删除builder中的一段
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);
this.count = count - len;
}
return this;
}
类似地还有deleteCharAt
public AbstractStringBuilder deleteCharAt(int index) {
checkIndex(index, count);
shift(index + 1, -1);
count--;
return this;
}
6. reverse方法
reverse()方法可以逆转字符的顺序。
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;
}
实际的方法就是双指针靠拢+交换、
StringBuffer
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuffer>, CharSequence
{
StringBuffer类几乎所有方法都是通过super关键字调用AbstractStringBuilder父类的方法。
StringBuffer实现同步的方式就是给所有方法加上synchronized关键字。
1. toStringCache变量
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient String toStringCache;
toStringCache缓存了toString()方法的最后一次调用的值,在每次StringBuffer被修改前这个缓存会清除。
toString()方法中检查如果有缓存,就直接返回缓存。这样不用每次都处理toString()的过程,而只在需要的时候处理。
public synchronized String toString() {
if (toStringCache == null) {
return toStringCache =
isLatin1() ? StringLatin1.newString(value, 0, count)
: StringUTF16.newString(value, 0, count);
}
return new String(toStringCache);
}
StringBuilder
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence
{
...
}
StringBuilder类几乎所有方法都是通过super关键字调用AbstractStringBuilder父类的方法。
JDK源码阅读(3):AbstractStringBuilder、StringBuffer、StringBuilder类阅读笔记的更多相关文章
- Java1.8 JDK源码中,对两个类进行 按位与 操作是什么意思
Java容器类库中的Map接口(java\util\Map.java)中有一个Entry接口(java\util\Map.java),其中有几个接口方法用到了类和类的按位与操作,即类和类之间有 &am ...
- JDK源码阅读顺序
很多java开发的小伙伴都会阅读jdk源码,然而确不知道应该从哪读起.以下为小编整理的通常所需阅读的源码范围. 标题为包名,后面序号为优先级1-4,优先级递减 1.java.lang 1) Obj ...
- JDK源码学习系列03----StringBuffer+StringBuilder
JDK源码学习系列03----StringBuffer+StringBuilder 由于前面学习了StringBuffer和StringBuilder的父类A ...
- 如何阅读JDK源码
JDK源码阅读笔记: https://github.com/kangjianwei/LearningJDK 如何阅读源码,是每个程序员需要面临的一项挑战. 为什么需要阅读源码?从实用性的角度来看,主要 ...
- 如何有效的阅读JDK源码
阅读Java源码的前提条件: 1.技术基础 在阅读源码之前,我们要有一定程度的技术基础的支持. 假如你从来都没有学过Java,也没有其它编程语言的基础,上来就啃<Core Java>,那样 ...
- 利用IDEA搭建JDK源码阅读环境
利用IDEA搭建JDK源码阅读环境 首先新建一个java基础项目 基础目录 source 源码 test 测试源码和入口 准备JDK源码 下图框起来的路径就是jdk的储存位置 打开jdk目录,找到sr ...
- jdk源码阅读笔记-HashSet
通过阅读源码发现,HashSet底层的实现源码其实就是调用HashMap的方法实现的,所以如果你阅读过HashMap或对HashMap比较熟悉的话,那么阅读HashSet就很轻松,也很容易理解了.我之 ...
- 如何阅读jdk源码?
简介 这篇文章主要讲述jdk本身的源码该如何阅读,关于各种框架的源码阅读我们后面再一起探讨. 笔者认为阅读源码主要包括下面几个步骤. 设定目标 凡事皆有目的,阅读源码也是一样. 从大的方面来说,我们阅 ...
- JDK源码阅读(三):ArraryList源码解析
今天来看一下ArrayList的源码 目录 介绍 继承结构 属性 构造方法 add方法 remove方法 修改方法 获取元素 size()方法 isEmpty方法 clear方法 循环数组 1.介绍 ...
- JDK源码阅读(一):Object源码分析
最近经过某大佬的建议准备阅读一下JDK的源码来提升一下自己 所以开始写JDK源码分析的文章 阅读JDK版本为1.8 目录 Object结构图 构造器 equals 方法 getClass 方法 has ...
随机推荐
- 【IDE】WebStorm常用快捷键
WebStorm常用快捷键 1. ctrl + shift + n: 打开工程中的文件,目的是打开当前工程下任意目录的文件. 2. ctrl + j: 输出模板 3. ctrl + b: 跳到变量申明 ...
- 初识javaScript(慕课网学习笔记)
js输出 window.alert() 警告框 document.write() 写到HTML文档中 innerHTML 写到HTML元素 console.log() 写到浏览器的控制台 <!D ...
- Git(GitHub)配合TortoiseGit使用
1.首先下载安装配置Git 安装请参照 https://www.cnblogs.com/xueweisuoyong/p/11914045.html 配置请参照 https://www.jianshu. ...
- js 中连续的 3 个点 three dots (...) in javascript
这个叫扩展运算符 https://dev.to/sagar/three-dots---in-javascript-26ci 5 种用法 1 function myFunc(...[x, y, z]) ...
- hash类型数据的操作指令
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.
- eBPF 安全项目 Tracee 初探
1. Tracee 介绍 1.1 Tracee 介绍 Tracee 是一个用 于 Linux 的运行时安全和取证工具.它使用 Linux eBPF 技术在运行时跟踪系统和应用程序,并分析收集的事件以检 ...
- IPSEC的实现方式
IPSEC的实现方式 在IPSEC通信中涉及到一个重要方面,那就是如何定义要保护的数据流(又称为感兴趣流).这不仅涉及到IPSEC最终要保护哪部分数据,还关系到IPSEC的实现方式,因此有必要把感兴趣 ...
- ubuntu 20.04 发邮件配置
安装sendmail后,发邮件一直没有成功,因此卸载sendmail后,安装heirloom-mailx. # unbuntu 18.04和20.04移除了heirloom-mailx,需要另外配置软 ...
- FileWriter文件文件字符输出流写入存储数据
1.FileWriter文件字符输出流-写入-存储数据 其中,流关闭之后再调用会报IOException; 其中,与文件字符输入流-写出-读取数据 和 字节输出流-写入-存储数据 不同的是,要先flu ...
- RSA及其证明 [原创]
描述RSA的实现步骤介绍文章非常多,但说明并证明其原理,并进而讨论为什么这样设计的文章不多.本人才疏学浅,不敢说理解了R.S.A.三位泰斗的设计初衷,简单就自己的理解写一写,博大家一笑. 以下原创内容 ...