String,String Builder,String Buffer-源码
String
String是一个很普通的类
源码分析
//该值用于字符存储
private final char value[];
//缓存字符串的哈希码
private int hash;// Default to 0
//这个是一个构造函数
//把传递进来的字符串对象value这个数组的值,
//赋值给构造的当前对象,hash的处理方式也一样。
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
//String的初始化有很多种
//空参数初始化
//String初始化
//字符数组初始化
//字节数组初始化
//通过StringBuffer,StringBuilder构造
问题: 我现正在准备构造一个String的对象,那original这个对象又是从何而来?是什么时候构造的呢?
测试一下:
public static void main(String[] args) {
String str = new String("zwt");
String str1 = new String("zwt");
}
在Java中,当值被双引号引起来(如本示例中的"abc"),JVM会去先检查看一看常量池里有没有abc这个对象,
如果没有,把abc初始化为对象放入常量池,如果有,直接返回常量池内容。

Java字符串两种声明方式在堆内存中不同的体现,
为了避免重复的创建对象,尽量使用String s1 ="123" 而不是String s1 = new String("123"),因为JVM对前者给做了优化。
常用的API
System.out.println(str.isEmpty());//判断是不是空字符串
System.out.println(str.length());//获取字符串长度
System.out.println(str.charAt(1));//获取指定位置的字符
System.out.println(str.substring(2, 3));//截取指定区间字符串
System.out.println(str.equals(str1));//比较字符串
isEmpty()
public boolean isEmpty() {
return value.length == 0;
}
length()
public int length() {
return value.length;
}
charAt()
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return value[index];
}
substring()
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
//如果截取的开始范围刚好是0并且结束范围等于数组的长度,直接返回当前对象,
//否则用该数组和传入的开始范围和结束范围重新构建String对象并返回。
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
equals()
public boolean equals(Object anObject) {
//如果是同一个引用,直接返回true
if (this == anObject) {
return true;
}
//判断是否是String
if (anObject instanceof String) {
//判断长度是否一致
String anotherString = (String)anObject;
int n = value.length;
//判断char[]里面的每一个值是否相等
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
equals()与“==”
这两者之间没有必然的联系,
在引用类型中,"=="是比较两个引用是否指向堆内存里的同一个地址(同一个对象),
而equals是一个普通的方法,该方法返回的结果依赖于自身的实现。
intern()
public native String intern();
//如果常量池中有当前String的值,就返回这个值,如果没有就加进去,返回这个值的引用,
一些基础
Java基本数据类型和引用类型
Java中一共有四类八种基本数据类型, 除掉这四类八种基本类型,其它的都是对象,也就是引用类型。
| 基本数据类型 | |
|---|---|
| 浮点类型 | float double |
| 字符型 | char |
| 逻辑型 | boolean |
| 整型 | byte short int long |

Java自动装箱/拆箱
Integer 里面我们曾经说过得 valueOf (), 这个加上valueOf方法的过程,就是Java中经常说的装箱过程。
在JDK1.5中,给这四类八种基本类型加入了包装类 。
第一类:整型
byte Byte
short Short
int Integer
long Long
第二类:浮点型
float Float
double Double
第三类:逻辑型
boolean Boolean
第四类:字符型
char Character
将int的变量转换成Integer对象,这个过程叫做装箱,
反之将Integer对象转换成int类型值,这个过程叫做拆箱。
以上这些装箱拆箱的方法是在编译成class文件时自动加上的,不需要程序员手工介入,因此又叫自动装箱/拆箱。
用处:
1、对象是对现实世界的模拟 。
2、为泛型提供了支持。
3、提供了丰富的属性和API
public static void main(String[] args) {
int int1 = 180;
Integer int2 = new Integer(180);
}
表现如下图:

StringBuilder
StringBuilder类被 final 所修饰,因此不能被继承。
StringBuilder类继承于 AbstractStringBuilder类。
实际上,AbstractStringBuilder类具体实现了可变字符序列的一系列操作,
比如:append()、insert()、delete()、replace()、charAt()方法等。
值得一提的是,StringBuffer也是继承于AbstractStringBuilder类。
StringBuilder类实现了2个接口:
Serializable 序列化接口,表示对象可以被序列化。
CharSequence 字符序列接口,提供了几个对字符序列进行只读访问的方法,
比如:length()、charAt()、subSequence()、toString()方法等。
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
定义的常量
//toString 返回的最后一个值的缓存。每当修改 StringBuffer 时清除。
private transient char[] toStringCache;
AbstractStringBuilder
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
//value 用来存储字符序列中的字符。value是一个动态的数组,当存储容量不足时,会对它进行扩容。
char[] value;
/**
* The count is the number of characters used.
*/
//count 表示value数组中已存储的字符数。
int count;
构造方法
public StringBuilder() {
super(16);
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
// AbstractStringBuilder.java
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
StringBuilder类提供了4个构造方法。构造方法主要完成了对value数组的初始化。
其中:
- 默认构造方法设置了value数组的初始容量为16。
- 第2个构造方法设置了value数组的初始容量为指定的大小。
- 第3个构造方法接受一个String对象作为参数,设置了value数组的初始容量为String对象的长度+16,并把String对象中的字符添加到value数组中。
- 第4个构造方法接受一个CharSequence对象作为参数,设置了value数组的初始容量为CharSequence对象的长度+16,并把CharSequence对象中的字符添加到value数组中。
append()方法
有多种实现,一般的顺序为:
append() ----> ensureCapacityInternal() 确保value数组有足够的容量 ----> newCapacity()新的容量
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
//扩容参数
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
在上面代码中可以看到具体的扩容规则是 * 2 + 2
StringBuffer
基本就是加了一个synchronized的StringBuilder。
StringBuilder 和 StringBuffer 适用的场景是什么?
stringbuffer固然是线程安全的,stringbuffer固然是比stringbuilder更慢,固然,在多线程的情况下,理论上是应该使用线程安全的stringbuffer的。
实际上基本没有什么地方显示你需要一个线程安全的string拼接器 。
stringbuffer基本没有适用场景,你应该在所有的情况下选择使用stringbuiler,除非你真的遇到了一个需要线程安全的场景 。
如果你遇见了,,,
stringbuffer的线程安全,仅仅是保证jvm不抛出异常顺利的往下执行而已,它可不保证逻辑正确和调用顺序正确。大多数时候,我们需要的不仅仅是线程安全,而是锁。
最后,为什么会有stringbuffer的存在,如果真的没有价值,为什么jdk会提供这个类?
答案太简单了,因为最早是没有stringbuilder的,sun的人不知处于何种考虑,决定让stringbuffer是线程安全的,
于是,在jdk1.5的时候,终于决定提供一个非线程安全的stringbuffer实现,并命名为stringbuilder。
顺便,javac好像大概也是从这个版本开始,把所有用加号连接的string运算都隐式的改写成stringbuilder,
也就是说,从jdk1.5开始,用加号拼接字符串已经几乎没有什么性能损失了。
扩展小知识
Java9改进了字符串(包括String、StringBuffer、StringBuilder)的实现。
在Java9以前字符串采用char[]数组来保存字符,因此字符串的每个字符占2字节,
而Java9的字符串采用byte[]数组再加一个encoding-flag字段来保存字符,因此字符串的每个字符只占1字节。
所以Java9的字符串更加节省空间,字符串的功能方法也没有受到影响。
参考链接
https://zhuanlan.zhihu.com/p/28216267
https://blog.csdn.net/u012317510/article/details/83721250
https://www.zhihu.com/question/20101840
String,String Builder,String Buffer-源码的更多相关文章
- String、StringBuffer、StringBuilder源码分析
利用反编译具体看看"+"的过程 1 public class Test 2 { 3 public static void main(String[] args) 4 { 5 int ...
- String、StringBuffer、StringBuilder源码解读
序 好长时间没有认真写博客了,过去的一年挺忙的.负责过数据库.线上运维环境.写代码.Code review等等东西挺多. 学习了不少多方面的东西,不过还是需要回归实际.加强内功,方能扛鼎. 去年学习M ...
- String类——StringBuilder类的源码及内存分析(java)
相同:底层均采用字符数组value来保存字符串 区别:String类的value数组有final 修饰,指向不可改,同时private 未提供修改value数组的方法.StringBuilder类的v ...
- String、StringBuffer和StringBuilder源码解析
1.String 1.1类的定义 public final class String implements java.io.Serializable, Comparable<String> ...
- netty(七)buffer源码学习2
概述 文章主要介绍的是PoolArena,PoolChunk,PoolSubpage 三个类的源码 PoolArena PoolArena 是netty 的内存池实现类,通过预先申请一块大的空间,然后 ...
- netty(六) buffer 源码分析
问题 : netty的 ByteBuff 和传统的ByteBuff的区别是什么? HeapByteBuf 和 DirectByteBuf 的区别 ? HeapByteBuf : 使用堆内存,缺点 ,s ...
- Buffer源码深入分析
博客园对MarkDown显示的层次感不是很好,大家可以看这里:Buffeer. 本机环境: Linux 4.4.0-21-generic #37-Ubuntu SMP Mon Apr 18 18:33 ...
- netty(八)buffer源码学习3
问题 : compositeByteBuf 是干什么和其他 compositeByteBuf 有何区别 内部实现 概述 compositeByteBuf 就像数据库中的视图,把几个表的字段组合在一起, ...
- string为什么是final?源码分析
http://blog.csdn.net/zhangjg_blog/article/details/18319521
- java.nio.Buffer源码阅读
Java 自从 JDK1.4 起,对各种 I/O 操作使用了 Buffer 和 Channel 技术.这种更接近于操作系统的的底层操作使得 I/O 操作速度得到大幅度提升,下面引用一段<Java ...
随机推荐
- 【模拟7.19】那一天我们许下约定(组合数学,DP)
看了题目名字深切怀疑出题人是不是失恋了,然后出题折磨我们.然后这题就愉快的打了个暴力,最后莫名其妙wa20,伤心..... 其实这题正解不是很难想,如果说把暴力的DP搞出来,正解也差不到哪去了, 我们 ...
- Pytorch项目基本结构
梳理一下Pytorch项目的基本结构(其实TF的也差不多是这样,这种思路可以迁移到别的深度学习框架中) 结构树 -------checkpoints #存放训练完成的模型文件 ----xxx.pk ...
- [翻译]在GC上加入DPAD
本文90%通过机器翻译,另外10%译者按照自己的理解进行翻译,和原文相比有所删减,可能与原文并不是一一对应,但是意思基本一致. 译者水平有限,如果错漏欢迎批评指正 译者@Bing Translator ...
- mapboxgl绘制3D线
最近遇到个需求,使用mapboxgl绘制行政区划图层,要求把行政区划拔高做出立体效果,以便突出显示. 拿到这个需求后,感觉很简单呀,只需要用fill-extrusion方式绘制就可以啦,实现出来是这个 ...
- Redis的数据安全与性能保障
1.持久化选项 Redis提供了2种不同的持久化方法来将数据存储到硬盘里面.一种方法叫快照(snapshotting),它可以将存在于某一时刻的所有数据都写入硬盘里.另一种方法叫只追加文件(appen ...
- 13、linux中用户和用户组
linux是多用户多进程的系统: 每个文件和进程都需要应对一个用户和用户组: linux系统通过uid和gid来识别用户和组的: 一个用户必须要有唯一的uid和一个主组来识别身份,不同的用户可以使用同 ...
- 8、ITSM基本概念(1)
ITSM即是信息技术服务管理: 8.1.什么是服务: 8.2.RACI模型: 谁负责(R =n Resposible),即负责执行任务的角色,他/她具体负责操控项目.解决问题. 谁批准(A = Acc ...
- [Usaco2018 Dec]Teamwork 题解
题目描述 题目描述 在Farmer John最喜欢的节日里,他想要给他的朋友们赠送一些礼物.由于他并不擅长包装礼物,他想要获得他的 奶牛们的帮助.你可能能够想到,奶牛们本身也不是很擅长包装礼物,而Fa ...
- SpringBoot | 1.3 约定编程Spring AOP
前言 前面聊过Spring的一个很重要的概念,IoC控制反转,接下来就是AOP了: 1. AOP切面编程 面向切面编程,是利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度 ...
- spring data jpa执行update和delete语句时报错处理
之前项目中使用spring data jpa时,遇到删除记录的需求时,主要利用spring data中自带的delete()方法处理,最近在dao层使用delete sql语句时报错,代码如下: @Q ...