JDK源码之StringBuffer与StringBuilder类分析
一 概述
- StringBuffer类被 final 所修饰,不能被继承,StringBuffer继承了AbstractStringBuilder类,
是一个可变的字符序列,并且类中方法都有synchronized修饰,实现了线程安全 - StringBuilder类也被final修饰,继承了AbstractStringBuilder类,与StringBuffer区别是没有实现线程安全,方法逻辑都是调用的父类方法逻辑
二 StringBuffer源码解析
大部分方法都调用super父类逻辑,所以这里只举个别例子, 父类解析地址: https://www.cnblogs.com/houzheng/p/12153734.html
/**
* 返回最后一次toString的缓存值,一旦StringBuffer被修改就清除这个缓存值,
* 用于toString方法的时候如果此值不为空,则直接使用返回,不必进行数组copy,以提高性能
*/
private transient String toStringCache;
/**
* 调用父类构造器进行byte数组初始化,默认长度初始化为16或者(32,jvm参数关闭压缩时)
*/
@HotSpotIntrinsicCandidate
public StringBuffer() {
super(16);
}
/**
* 指定byte数组长度初始化
*/
@HotSpotIntrinsicCandidate
public StringBuffer(int capacity) {
super(capacity);
}
/**
* 根据String参数初始化
*/
@HotSpotIntrinsicCandidate
public StringBuffer(String str) {
super(str.length() + 16); //先进行初始化
append(str); //添加str
}
/**
* StringBuffer中所有方法都有synchronized修饰,保证了线程安全
* 每次操作都是对原有的byte数组操作,然后返回当前实例,从而实现了可变序列
* 几乎所有方法都是调用父类的方法逻辑,再加上synchronized实现,比如下面的append
*/
@Override
@HotSpotIntrinsicCandidate
public synchronized StringBuffer append(String str) {
toStringCache = null; //清空缓存
super.append(str);
return this; //返回this实例
}
// 覆写的toString方法,每次都是new一个String对象,如果toStringCache不为空,则直接用toStringCache构造String对象,否则进行数组copy
@Override
@HotSpotIntrinsicCandidate
public synchronized String toString() {
if (toStringCache == null) {
return toStringCache =
isLatin1() ? StringLatin1.newString(value, 0, count)
: StringUTF16.newString(value, 0, count);
}
return new String(toStringCache);
}
/**
* 自定义序列化字段,即序列化只序列化数组里面的属性
* ObjectStreamField类型数组serialPersistentFields定义需要被自动序列化的字段,
* 而且一旦定义了这个属性,那么就不会识别原本默认的可序列化字段,例如非static和非transitent字段。
*/
private static final java.io.ObjectStreamField[] serialPersistentFields =
{
new java.io.ObjectStreamField("value", char[].class),
new java.io.ObjectStreamField("count", Integer.TYPE),
new java.io.ObjectStreamField("shared", Boolean.TYPE),
};
/**
* 自定义序列化:
* 在序列化过程中,如果被序列化的类中定义了writeObject 和 readObject 方法,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法(利用反射实现),
* 进行用户自定义的序列化和反序列化。
* 如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。
* 用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。
*/
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
java.io.ObjectOutputStream.PutField fields = s.putFields();
char[] val = new char[capacity()];
if (isLatin1()) {
StringLatin1.getChars(value, 0, count, val, 0);
} else {
StringUTF16.getChars(value, 0, count, val, 0);
}
//自定义序列化三个字段
fields.put("value", val);
fields.put("count", count);
fields.put("shared", false);
s.writeFields();
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
java.io.ObjectInputStream.GetField fields = s.readFields();
//反序列化只获取value 和 count
char[] val = (char[])fields.get("value", null);
initBytes(val, 0, val.length);
count = fields.get("count", 0);
}
三 StringBuilder源码解析
StringBUilder与StringBuffer基本一样,只是自我实现没有保证线程安全以及自定义序列化字段的一些区别
// 默认byte数组初始化为16
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
/**
* 被@HotSpotIntrinsicCandidate标注的方法,在HotSpot中都有一套高效的实现,该高效实现基于CPU指令,
* 运行时,HotSpot维护的高效实现会替代JDK的源码实现,从而获得更高的效率。
*/
@HotSpotIntrinsicCandidate
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
@Override
@HotSpotIntrinsicCandidate
public StringBuilder append(String str) {
super.append(str); //调用父类方法
return this;
}
//自定义序列化直接序列化
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeInt(count);//序列化 count,实际占用长度
char[] val = new char[capacity()];
if (isLatin1()) {
StringLatin1.getChars(value, 0, count, val, 0);
} else {
StringUTF16.getChars(value, 0, count, val, 0);
}
s.writeObject(val); // 序列化 char数组
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
count = s.readInt();
char[] val = (char[]) s.readObject();
initBytes(val, 0, val.length);
}
四 总结
- StringBuffer相比String来说,性能更高,因为不用每次去生成一个String实例,尤其是for循环中
- StringBuilder性能会更好,他与StringBuffer都是继承了一样的父类,区别是各自的实现不同,一个线程安全,一个非线程安全
- String适用于少量的字符串操作的情况
- StringBuilder适用于单线程下在字符缓冲区进行大量操作的情况
- StringBuffer适用多线程下在字符缓冲区进行大量操作的情况
JDK源码之StringBuffer与StringBuilder类分析的更多相关文章
- JDK源码学习系列03----StringBuffer+StringBuilder
JDK源码学习系列03----StringBuffer+StringBuilder 由于前面学习了StringBuffer和StringBuilder的父类A ...
- Java基础(八)--String(源码)、StringBuffer、StringBuilder
String源码:基于jdk1.8 public final class String implements Serializable, Comparable<String>, CharS ...
- JDK源码学习之 集合实现类
一.HashMap (1) 简介:java1.8版本之前HashMap的结构图如下: 数组的每个元素都是一个单链表的头节点,链表是用来解决冲突的,如果不同的key映射到了数组的同一位置处,就将其放入单 ...
- JDK源码阅读(7):ConcurrentHashMap类阅读笔记
ConcurrentHashMap public class ConcurrentHashMap<K,V> extends AbstractMap<K,V> implement ...
- JDK源码阅读(4):HashMap类阅读笔记
HashMap public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, ...
- JDK源码阅读--StringBuffer
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharS ...
- JDK源码阅读(5):HashTable类阅读笔记
HashTable public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, ...
- JDK源码分析之concurrent包(三) -- Future方式的实现
上一篇我们基于JDK的源码对线程池ThreadPoolExecutor的实现做了分析,本篇来对Executor框架中另一种典型用法Future方式做源码解读.我们知道Future方式实现了带有返回值的 ...
- Java中集合框架,Collection接口、Set接口、List接口、Map接口,已经常用的它们的实现类,简单的JDK源码分析底层实现
(一)集合框架: Java语言的设计者对常用的数据结构和算法做了一些规范(接口)和实现(实现接口的类).所有抽象出来的数据结构和操作(算法)统称为集合框架. 程序员在具体应用的时候,不必考虑数据结构和 ...
随机推荐
- NOIP2009 压轴---最优贸易
链接:https://ac.nowcoder.com/acm/contest/959/H来源:牛客网 C国有n个大城市和m条道路,每条道路连接这n个城市中的某两个城市.任意两个城市之间最多只有一条道路 ...
- 2019 秦皇岛CCPC赛后总结
以前一直想参加ICPC或CCPC的,所以即使得知比赛会打星号,我还是想去. 感觉自己对什么都没有兴趣了,比较渴望找点快乐.. 这场比赛非常强,吉老师和杜老师都来啦,还有岛娘! 有幸要到了签名 滚榜的时 ...
- 只用这 6 个字符,就可以写出任意 JavaScript 代码!
你可能在网上见过有人用 几个不同的字符写的各种稀奇古怪的 JavaScript 代码,虽然看起来奇怪,但是能正常运行!比如这个: (!(~+[])+{})[--[~+""][+[] ...
- 【python小随笔】celery异步任务与调用返回值
s1.py(配置任务文件) from celery import Celery import time my_task = Celery("tasks", broker=" ...
- 【题解/模板】P1248 加工生产调度(贪心)
[题解/模板]P1248 加工生产调度(贪心) 分析: \(A\)流水线的时间是确定的,所以现在就是要让\(b\)的时间尽量短 \(tB > tA\),除非所有东西都不需要\(b\).(t指结束 ...
- $CF311B\ Cats\ Transport$ 斜率优化
AcWing Description Sol 设f[i][j]表示前i个饲养员接走前j只猫咪的最小等待时间. 要接到j猫咪,饲养员的最早出发时间是可求的,设为d: $ d[j]=Tj-\sum_{k= ...
- DRF 08
目录 三大认证 流程 认证组件 权限组件 频率组件 自定义token的签发 三大认证 流程 由于DRF中, 所有的视图类都要直接和间接继承APIView类, 也只有APIView类中才有dispatc ...
- ASP.NET Core 中间件的几种实现方式
前言 ASP.NET Core 中 HTTP 管道使用中间件组合处理的方式, 换句人话来说, 对于写代码的人而言,一切皆中间件. 业务逻辑/数据访问/等等一切都需要以中间件的方式来呈现. 那么我们必须 ...
- 「BZOJ4510」「Usaco2016 Jan」Radio Contact 解题报告
无线电联系 Radio Contact 题目描述 Farmer John has lost his favorite cow bell, and Bessie the cow has agreed t ...
- doc_values VS stored field
doc_values 按列存储,按docId排序,在query阶段使用,直接根据docId获取具体field的value,用来排序,聚合等. stored field按文档存储,按docId排序,一条 ...