String StringBuffer StringBuilder

1. String类

String表示字符串类型,属于引用数据类型,不属于基本数据类型。java中规定,双引号括起来的字符串,是不可变的,线程安全

String类的底层结构为(jdk9之前):

private final char value[];

String类的底层结构为(jdk9之后):

private final byte value[];

String类不可变的分析:

public final class String类是由final修饰的类,所以String不可继承。

String类的底层为private final char value[],由final修饰的字符数组的内存地址不可改变,并且是private的访问权限并且没有提供getter/setter方法,所以外部不能对字符数组进行操作。


String类的性能分析:

①如String s1 = "a":JVM会将字符串a保存到常量池中

②如String s2 = new String("b"):JVM会将字符串b放在常量池中管理,在调用String类的构造器创建一个对象,对象保存堆内存中

image-20220723150411667

2. StringBuffer类 StringBuilder类

当对字符串进行修改的时候,需要使用 StringBufferStringBuilder 类。和String类不同的是,StringBufferStringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

StringBuffer类与StringBuilder类都有共同的父类AbstractStringBuilder类,但由于StringBuffer类对方法都加了synchronized关键字,所以StringBuffer是线程安全的类,StringBuilder是线程不安全的类。


StringBufferStringBuilder类的底层结构都是是由父类的char value[],所以这两个对象是可变的。

StringBuffer类的构造器:

①空参构造器

// String类的构造器
public StringBuffer() {
    super(16);
}

// AbstractStringBuilder类
char[] value;
AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

new StringBuffer():将调用父类的构造器,初始化一个长度为16的字符数组

②有参构造器

public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
}

new StringBuffer(String str):将调用父类的构造器,初始化一个字符串str的长度+16的字符数组


StringBuffer的扩容机制:

StringBuffer类的append()方法调用的父类的append()方法

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;
}

父类的append()方法中调用了ensureCapacityInternal()方法,count指的是已有的字符串的长度,len为待插入的字符串的长度。

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
        newCapacity(minimumCapacity));
    }
}

ensureCapacityInternal()方法中的minimumCapacity就是上面的count + lenvalue.length就是要char[] value数组的长度。所以,当要插入的字符串的长度 + 原有的字符串长度 > 存储空间的长度时,就要进行扩容。

最后,通过newCapacity()方法获得新的容量,在用Arrays.copyOf()方法复制数组。

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;
    }

newCapacity()方法先将新的容量设置为原来容量的两倍 + 2,如果扩充的容量还不够,直接扩充到需要的容量大小。

posted @ 2022-07-23 16:05  Lyfzzz  阅读(36)  评论(0)    收藏  举报