一:String
1.1 继承结构
1
String 实现序列化标志接口,可以被序列化
2
String 实现比较器接口,也就是Set等集合元素为String可以使用其比较器排序
3
String 实现字符序列接口,CharSequence也被StringBuilder等实现
1.2 初始化类型
1
字面量:初始化后的字符串位于常量池中
2
对象实例:构造函数new实例化后的对象位于堆内存。重载形式较多,String底层采用char[]数组存储数据,有参构造可为String、int[]、char[]、byte[]等形式
1.3 特点描述
1
类被final修饰,意味着不能被继承、反射等操作,String不能被动态代理
2
存储元素的char[]类型属性value被final修饰,意味着值不能更改,也就是String每次更改都会生成新对象
1.4 intern()解析
初始化说了字符串有常量与堆内存两种内存地址,引发了字面常量与字符串对象比较的系列问题:
false
false
true
1
调用intern()如果常量池中没有字符串则将对内存地址复制一份放入常量池
2
new实例化字符串对象时不仅仅在堆中生成字符串对象,同时常量池存在对应字面量
3
通过2可以很好解释s3与s4不相等,因为new实例化s3时常量池就已经存在其字面量
二:StringBuffer/StringBuilder
2.1 继承结构
主要看准这个Appendable接口,该接口提供append()等系列重载实现。而且再看下图所示AbstractStringBuilder:
1
存储元素的char[]类型属性value没被final关键字修饰,也就意味着可以进行对应的修改
2
count属性记录该数组使用情况,也就是下标操作,配合进行数组扩容
2.2 内容修改与动态扩容
StringBuilder类中append()的返回值充分说明进行元素变更后的字符串对象还是原对象,返回的是this,接下来再深入看父类AbstractStringBuilder的append()实现
父类实现中主要是两个模块ensureCapacityInternal()数组扩容算法实现与String提供的getChars()进行内容变更。其中getChars()就是调用System.arraycopy()实现,重点关心数组扩容实现
1
首先判断value数组已使用数量 + 将消耗数量与数组长度的比较,大于则进行扩容
2
扩容时获取原长度两倍 + 2 的容量
3
如果这个容量还是小于扩容后应达最小容量则将最小容量设置为扩容后容量
4
设置完毕进行溢出判断并设置为Integer最大数量
5
赋值原数组元素到扩容后数组
注意
:看完扩容算法后其实个人是有点想法,首先扩大两倍基本考虑是一次满足客户需求,当不够的时候会直接使用刚好的长度。也就意味着下次变化一定会发生扩容,所以执行append()的时候最好别一次追加相对于原对象过长内容
2.3 线程安全
StringBuffer相对于StringBuilder是线程安全实现,线程安全就是使用了Synchronized进行保证。当然不可避免StringBuilder相对于StringBuffer效率更高
三:StringJoiner
JDK1.8提供具有强大API的字符串操作类,底层采用StringBuilder
实现,线程非安全。在前缀
、后缀
、分隔
方面表现优异
3.1 重要属性
1 prefix前缀、suffix后缀在最终返回字符串前添加的内容
2 delimiter前后缀与主题内容value之间的分隔符
3 Stringbuilder类型的value属性记录内容
4 emptyValue默认为prefix+suffix,当value为空时,toString()返回内容
3.2 构造函数
构造函数就两个,前后缀默认为"",分隔符是必须传递的参数
3.3 元素添加
元素添加就是调用上述方法后执行StringBuilder的appen方法,上图方法就一个目的。如果value也就是内容不为空直接拼接上分隔符即可。如果内容为空则需要实例化空对象StringBuilder后加上前缀即可