Java中StringBuilder类和StringBuffer类的区别

Java语法中规定的字符串String类是一种不可变对象,字符串中的内容是不可变的。
查看源码我们发现,这是因为String类中的字符实际上保存在内部维护的 value 字符数组中,value 被 final 修饰,表明 value 自身的值不能被改变(具有原子性)。image.png
一旦一个 String 对象被创建后,包含在这个对象中的字符是不可变的,直到这个对象被销毁或者指向别的对象。
每次对String对象的操作例如 str = str1+str2,看似是拼接了,实际上是新生成了一个String对象,然后将指针指向新的String对象。所以经常改变字符串的内容不建议用String,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了之后,JVM的GC就会开始工作,性能就会降低。
为此Java提供了两个可变的字符串类:StringBuilderStringBuffer, 并且提供了操作自身对象的一些方法.
我们先看一下源码,然后分析一下这两个类的不同:


一、源码分析:

StringBuilder类:微信截图_20231110145041.png
StringBuffer类:
image.png

分析源码我们可以发现这两个类都继承了 AbstractStringBuilder 父类,并且实现的接口都是一样的。
java-string-20201208.png
两个类的大部分功能都是相似的,目的都是为了解决String 的不可变性提供的方便的字符串缓冲区
不一样的地方:
在StringBuffer类中的操作方法都会被 synchronized 关键字修饰,说明它在实现上是一个线程安全的可变的字符序列,可供多个线程使用。而StringBuilder 则不保证这一点。
微信截图_20231110145143.png
这个就是 两个类之间最本质的区别,设计意义上 String 和 StringBuffer 都是Java本身语法自带的,StringBuilder 则是 jdk1.5 之后更新的类。
StringBulider 提供与 StringBuffer 兼容的 API,但
不保证同步
。官方文档中称其为StringBuffer 的替代品,并提倡在可能的情况下,建议使用 StringBuilder类 优先于 StringBuffer,因为在大多数实现中它会更快
StringBuilder 比 StringBuffer 快,可以这样理解:使用synchronized关键字修饰之后就会涉及到频繁的加锁释放锁的操作,会消耗系统的资源,时间上也会花费的更多。但是为了保证线程安全,这些时间和空间的牺牲是必要的。


二、比较的结果:

不同点:

  • StringBuffer 采用同步处理,线程安全;StringBuilder 未采用同步处理,线程不安全;
  • StringBuffer 相对来说速度比 StringBuilder 慢。

相同点:

  • StringBuffer 和 StringBuilder 实现的对字符串的操作方法是一样的
  • StringBuffer 和 StringBuilder 都是在自身基础上进行的修改操作,没有像String 会生成新的对象再改变引用指向。

三、总结:

没有完美的即保证线程安全又不影响性能的类,因为想实现一些东西就要舍弃一些东西,欲戴王冠必承其重。
StringBufferStringBuilder 在设计上就是为了适应不同的场景,它们各有所长。

StringBuilder:
通常在单线程情况下操作数据用StringBuild,例如比较简单的项目场景(确保不涉及多线程情况)、刷力扣题时,因为涉及不到线程安全问题,使用StringBuilder更高效一些。
StringBuffer:
多线程环境情况下,使用 StringBuffer。看我们项目模块的环境来权衡。


四、常见的情景方法:

String 类具有的一些操作的方法,例如拆分(split)、截取(substring)、替换(replace)… 这些都不是在原来的基础对象上进行操作,而是产生一个新的字符串再改变引用指向,因为String 是不可变的
最后介绍一下常用的StringBuilder、StringBuffer的方法,它们提供了额外的操作方法,实现上也是在自身进行的改变,没有新创建对象。
两个类提供的方法类名、参数大部分都一样,按情况调用即可。

1、添加:append(E value)

T 类型(这里的 T 类型代表八种基类类型 & String类型 & Object类型数据,下文相同的参数以字符串表示形式追加到序列中。举例:

public static void main(String[] args) {
    String s = "wend";
    StringBuilder str= new StringBuilder(s);
    str.append(123);
    System.out.println(str);
}
//输出结果:wend123

2、插入:insert(int offect,T value)

在offert 位置插入T 类型数据。注意插入位置是在 offect 元素前面,即插入后value在offect的位置,举例:

public static void main(String[] args) {
        String s = "wend";
        StringBuilder str= new StringBuilder(s);
        str.insert(1,123);
        System.out.println(str);
}
//输出结果:w123end

3、删除:delete(int start,int end)

删除[start,end)区间内的字符,区间:左闭右开。举例:

 public static void main(String[] args) {
        String s = "wend";
        StringBuilder str= new StringBuilder(s);
        str.delete(1, 2);
        System.out.println(str);
}
//输出结果:wnd

4、反转:reserve()

将自身字符串序列翻转过来,举例:

public static void main(String[] args) {
        String s = "wend";
        StringBuilder str= new StringBuilder(s);
        str.reverse();
        System.out.println(str);
}
//输出结果:dnew
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值