StringBuilder和StringBuffer和String

StringBuilder和StringBuffer和String的区别

StringBuilder、StringBuffer和String的区别

拼接字符串:

StringBuilderStringBuffer拼接字符串,直接可以输出拼接后的结果

String不接收字符串,返回的还是原来的空字符串;接收为str2则返回拼接后的结果

// StringBuilder声明的stringbuilder
StringBuilder stringbuilder = new StringBuilder();
stringbuilder.append("aaa");
System.out.println(stringbuilder);    // aaa

// StringBuffer声明的stringbuffer
StringBuffer stringbuffer = new StringBuffer();
stringbuffer.append("aaa");
System.out.println(stringbuffer);    // aaa

// String声明的str1
String str1 = new String();
str1.concat("aaa");
String str2 = str1.concat("ccc");
System.out.println(str1);    // 空字符串
System.out.println(str2);    // ccc

String

不可变字符串,不可以改变长度和内容

1、String字符串底层使用final修饰value[] 数组,所以不可以改变内容和新的指向

// String 底层存储字符串源码
private final char value[];

2、String类中的所有方法,返回值是new一个新的字符串

例如:concat("字符串")拼接字符串,可以看到return 返回的是new String(),没有改变当前的字符串

// concat() 方法底层源码
public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    int len = value.length;
    char buf[] = Arrays.copyOf(value, len + otherLen);
    str.getChars(buf, len);
    return new String(buf, true);
}

StringBuilder和StringBuffer

可变字符串,可以改变长度和内容

1、String字符串底层,没有使用final修饰value[] 数组,所以vlaue只是一个普通字符数组

// StringBuilder和StringBuffer 底层存储字符串源码
char[] value;

2、StringBuilderStringBuffer类中的所有方法,返回值是this当前字符串

例如:append("字符串")拼接字符串,返回值都是this,代表返回的值都是当前的字符串

// StringBuffer的append()方法底层源码
@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}
// StringBuilder的append()方法底层源码
@Override
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

StringBuilder和StringBuffer的区别

区别StringBuliderStringBuffer
线程安全性不安全安全
性能

StringBuffer 的线程安全性

StringBuffer被设计为线程安全的类。它的所有公开方法(如append(), insert(), delete(), 等等)都是使用synchronized关键字修饰的。这意味着在任意时刻,只有一个线程能够执行StringBuffer的某个方法。这种同步机制确保了多线程环境下对StringBuffer对象的并发访问不会导致数据不一致或损坏。

例如,如果有两个线程同时尝试向同一个StringBuffer对象追加数据,synchronized关键字会确保一个线程完成其操作之前,另一个线程不会开始其操作。这种机制虽然保证了线程安全,但也带来了性能上的开销,所以相对性能低。

StringBuilder 的非线程安全性

StringBuilder没有使用synchronized关键字来修饰其方法。这意味着在多线程环境下,多个线程可以同时访问和修改同一个StringBuilder对象,而不需要等待其他线程完成其操作。虽然这提高了性能,但也带来了线程安全性的问题。

如果在多线程环境中使用StringBuilder,并且多个线程同时修改同一个StringBuilder对象,就可能导致数据不一致或损坏。例如,一个线程可能正在向StringBuilder中追加数据,而另一个线程可能同时也在进行追加操作,这可能导致数据被覆盖或混淆。

扩容方式

因为StringBuffer StringBuilder 继承的是同一个类AbstractStringBuilder

并且append方法都调用的是父类的append方法,所以这里直接看父类的扩容方式

// 源码:
// AbstractStringBuilder父类中的append方法
public AbstractStringBuilder append(String str) {
    if (str == null)   // 判断添加的内容是否为空
        return appendNull();   // 调用添加null方法,将null追加到字符串末尾
    int len = str.length();    // 追加字符串的长度
    ensureCapacityInternal(count + len);   // 扩容
    str.getChars(0, len, value, count);
    count += len;   
    return this;   // 返回当前字符串
}

// ensureCapacityInternal()方法
private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {  // 如果需要的长度大于现有的长度
        value = Arrays.copyOf(value, 
                newCapacity(minimumCapacity));  // 进行扩容,获取新的长度
    }
}

// newCapacity()方法 扩容机智的底层
private int (int minCapacity) {
    // overflow-conscious code
    int newCapacity = (value.length << 1) + 2;   // 先扩大原长度的2倍+2
    if (newCapacity - minCapacity < 0) {    // 如果扩大2n+2后,还是不足需要的长度
        newCapacity = minCapacity;		// 直接将需要的长度赋值给新扩容的长度
    }
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}
  • 当向 StringBuilderStringBuffer 中追加内容导致当前容量不足时,它们会进行扩容。
  • 扩容的新容量通常是当前容量的两倍再加一个额外的值2。
  • 扩容时,会创建一个新的字符数组,并将原有内容复制到新数组中,然后更新内部引用以指向新的字符数组。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值