String底层详解
String的底层实现原理
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; 复制代码
可以看到 String 是被final所修饰的,这意味着String不可被继承 同样可以看到String的底层其实是一个char型的数组,同样被final修饰,变成了常量。 这里提一嘴fianl ,final可以修饰类,方法,变量 被fianl修饰的类不可被继承,被final修饰的方法不可被重载, 被fianl修饰的变量会变成常量,一经初始不可更改 复制代码
String的赋值
String的运用有两种,一种是"=" 号直接赋值,另一种是new String("xxx")赋值 这两种是有区别的,首先说"="号赋值的这种 复制代码
String str = "abc"; 复制代码
"=" 号的赋值方式并不会在堆上创建新的对象,而是在常量池中搜索 如果常量池中有这个字符则直接引用这个字符的地址 如果没有这个字符,则会在常量池中创建该字符,并引用地址 字符常量池中不存在两个相同的字符,也就是说 复制代码
String str1 = "abc"; String str1 = "abc"; System.out.println(str1==str2);//true //二者引用的地址是相同的,都指向一个字符 复制代码
String str2=new String("abc"); 复制代码
new String() 意味着创建了一个新的对象,就意味着会在堆上分配一块内存 但并不是说这个字符就存储在了堆上,而是存储了一个地址,这个地址仍然指向字符常量池 有人说字符已经初始就不可更改了,那我要是像更改有什么办法嘛 复制代码
String str="abc"; System.out.println(str); System.out.println(str+"456"); System.out.println(System.identityHashCode(str)); System.out.println(System.identityHashCode(str+"456")); 输出结果: abc abc456 1528902577 1927950199 复制代码
可以看出虽然用"+"号似乎可以增加新的字符,但是缺并不是原先的对象了,二者内存地址不同 而且也只能进行字符添加,要想修改字符的内容,就要看下面两个类了 复制代码
StringBuffer和StringBuilder
这是我找到的一张关系图,可以看出 StringBuffer和StringBuilder都是继承自AbstractStringBuilder
要想改变字符,StringBuffer和StringBuilder都为我们提供了一些方法 增加字符:append 方法 删除字符:delete 方法 反转字符:revers 方法 替换字符: replace 方法 还有一些其他方法就留着下回探索 复制代码
既然两个类都可以对字符进行修改,哪两者到底有什么区别呢?
StringBuffer是线程安全的,StringBuilder是非线程安全的 其实就是StringBuffer在一些方法加上了synchronized关键字加锁了 这样他就可以支持并发操作 在不考虑并发的情况下,StringBuilder的效率是要高于StringBuffer的 因为不需要加锁和释放锁 复制代码
扩容机制:
public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence { private transient char[] toStringCache; static final long serialVersionUID = 3388685877147921107L; public StringBuffer() { super(16); } 复制代码
可以看见,StringBuffer数组的初始长度是16(StringBuilder也是),当长度不够的时候, 会触发扩容机制,会创建一个新的数组,长度是原数组的二倍+2,再把原数组的元素复制过去 复制代码
private int newCapacity(int minCapacity) { // overflow-conscious code 扩大2倍+2 //这里可能会溢出,溢出后是负数哈,注意 int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } //MAX_ARRAY_SIZE的值是Integer.MAX_VALUE - 8,先判断一下预期容量(newCapacity)是否在0<x<MAX_ARRAY_SIZE之间,在这区间内就直接将数值返回,不在这区间就去判断一下是否溢出 return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; }
作者:冷漠的麻辣烫
链接:https://juejin.cn/post/7018392166837780493