一、Java 中操作字符串都有哪些类?它们之间有什么区别?
String、StringBuffer、StringBuilder
String : final修饰,是不可变的,所以线程安全,String类的方法都是返回new String。即对String对象的任何改变都不影响到原对象,对字符串的修改操作都会生成新的对象
- //String类是final修饰,底层是用char数组来存储,也是用final修饰,不可变的类都是线程安全的
- public final class String
- implements java.io.Serializable, Comparable
, CharSequence { - //存放数组
- private final char value[];
- }
StringBuffer:线程安全的,对字符串的操作的方法都加了synchronized,保证线程安全
StringBuilder :线程不安全
- //StringBuffer与StringBuilder都继承AbstractStringBuilder,底层也是用char数组存储
- public final class StringBuilder
- extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence {
- //默认数组长度16
- public StringBuilder() {
- super(16);
- }
- //如果调用有参构造,长度则为16 + 字符串长度
- public StringBuffer(String str) {
- super(str.length() + 16);
- append(str);
- }
-
- //StringBuilder与StringBuffer在appen时都调用父类的append方法
- @Override
- public StringBuilder append(String str) {
- super.append(str);
- return this;
- }
- }
-
- public final class StringBuffer
- extends AbstractStringBuilder
- implements java.io.Serializable, CharSequence {
-
- public StringBuffer() {
- super(16);
- }
-
- public StringBuffer(String str) {
- super(str.length() + 16);
- append(str);
- }
-
- //StringBuffer类中,所有的方法都加了synchronized,所以线程安全
- @Override
- public synchronized StringBuffer append(String str) {
- toStringCache = null;
- super.append(str);
- return this;
- }
- }
-
- //StringBuffer与StringBuilder的父类
- abstract class AbstractStringBuilder implements Appendable, CharSequence {
- //用char数组来存放数据,没有用final修饰,所以可变
- char[] value;
- //字符串具体的长度, char数组的长度!=字符串长度
- int count;
-
- //char数组的长度调用capacity方法
- public int capacity() {
- return value.length;
- }
-
- //每次调用append时,都产生一个新的char数组,并两次进行数组copy
- public AbstractStringBuilder append(String str) {
- if (str == null)
- return appendNull();
- int len = str.length();
- //数组扩容,每次复制一个新的数组
- ensureCapacityInternal(count + len);
- //将要添加的字符串复制到新数组中
- str.getChars(0, len, value, count);
- count += len;
- return this;
- }
- }
-
二、StringBuffer与StringBuilder底层扩容机制
- abstract class AbstractStringBuilder implements Appendable, CharSequence {
- //底层扩容,调用数组copyOf方法
- private void ensureCapacityInternal(int minimumCapacity) {
- //如果append时,最小长度大于当前数组的长度,出发扩容
- if (minimumCapacity - value.length > 0) {
- value = Arrays.copyOf(value,
- newCapacity(minimumCapacity));
- }
- }
-
- private int newCapacity(int minCapacity) {
- //扩容后新数组的长度 = 老数组的长度2倍 + 2
- int newCapacity = (value.length << 1) + 2;
- if (newCapacity - minCapacity < 0) {
- newCapacity = minCapacity;
- }
- //不超过int最大范围
- return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
- ? hugeCapacity(minCapacity)
- : newCapacity;
- }
- }
三、string类为什么是final的?
主要是为了“效率” 和 “安全性” 的缘故。
1、 由于String类不能被继承,所以就不会没修改,这就避免了因为继承引起的安全隐患
2、若 String允许被继承, 由于它的高度被使用率, 可能会降低程序的性能,所以String被定义成final。
String存放数据的char数组value用final修饰,表示该数组引用地址不可变,数组中内容可以通过反射来修改