(二)String,StringBuffer和StringBuilder的区别

这是一个非常初级也是一个老生常谈的问题了,最近准备面试,温习了一遍,索性写下来我自己的理解吧,我学习一般喜欢去源码看一下,我们先来概括一下他们的区别,然后分头看一下就可以了。

1.概念

String  字符串常量

StringBuffer 线程安全的字符串变量

StringBuilder  非线程安全的字符串变量

2.StringBuffer和StringBuilder相对于String的优势

为什么说String是一个字符串常量,而StringBffer和StringBuilder是一个字符串变量呢,我们看下源码,

这个是String类里定义的一个数组
 @Stable
    private final byte[] value;
而StringBuffer和StringBuilder中value的值是这样定义的
  byte[] value;

这里value就是我们调用用到String,StringBuffer,StringBuilder的时候传入得参数,我们可以看到,String底层实现其实是一个用final修饰的不可变的数组,而StringBuffer和StringBuilder并没有final修饰,是可变的。为什么我们要讲他可变不可变,到底都有什么好处呢,我们来看一一个例子:

        String i = "a";
        String j = "b";
        String k = i+j;
        StringBuilder sb = new StringBuilder("a").append("b");

我们可以看到,由于String是不可变的,所以我们在最终得到常量k的时候其实已经创建了三次对象,分别是i,j,k。而我们日常开发中不可避免的会对字符串内容做更改的,如此我们就会创建许多无用的对象,如此内存中无用的对象多了以后GC会对其进行垃圾回收,这个过程是极其慢的,会对我们系统的性能产生或多或少的一些影响。

而我们看到StringBuffer或者StringBuilder相比于String的优势就在于它是一个可以修改的数组,所以我们在进行字符串拼接的时候并不用创建无用对象,我们GC也不用做过多回收。

值得一提的是,这里需要注意一点,有的人可能会问,我们为什么要创建对象i,j,直接像下面这样写不就好了

String k = "a"+"b";

这样是不是就少创建了两个对象,是的,这样做确实少创建了两个对象,我们来反编译一下

C:\javacode\JavaCase\out\production\JavaCase>javap -c Main
Compiled from "Main.java"
public class Main {
  public Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String abc
       2: astore_1
       3: return
}

我们可以看到,jvm直接把它视为了一个常量,至于初始化速度与Stringbuffer,StringBuidler是没差的,但我们依然推崇使用StringBuffer,为什么。因为我们依然无法保证字符串在后续使用中不做改动,一旦其他地方引用到,我们依然要去多创建一个甚至多个对象去实现我们的业务功能。

3.StringBuffer和StringBuilder的区别

上文已经提到,StringBuffer是线程安全的,StringBuilder是非线程安全的,何为线程安全,就是可以安全的在多线程环境下通过同步机制使得各个线程都可以正常且正确的执行,不会出现共享数据时产生数据的污染。那么我们具体来看一下这两者的实现

这是StringBuffer的append方法的实现  
@Override
    @HotSpotIntrinsicCandidate
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
这是StringBuilder的append方法的实现
@Override
    @HotSpotIntrinsicCandidate
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

我们可以显而易见的看到StringBuffer的append方法是加了一个synchronized同步锁的,这也就保证了我们上面说的在多线程环境下操作时,所有操作都会以线程串行的顺序执行线程操作,很多地方有在讨论StringBuilder的性能比StringBuffer好,因为锁的存在,大量线程同时访问同一条数据会造成线程阻塞,其实不然,我们忽略了一个重要的场景就是在我从业不长的两三年生涯中至今没有遇到一个需要线程安全的string拼接器!!!所以大家只需要理解一下这个原理即可,实操环境下,必定是推荐使用StringBuilder的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值