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;
}
复制代码

猜你喜欢

转载自juejin.im/post/7018392166837780493
今日推荐