String和StringBuffer和StringBuilder的区别

因为String是不可变的,StringBuffer 和 StringBuilder 它们都是可变的字符串,不过它们之间的区别是 Java 初中级面试出现几率十分高的一道题。这么简单的一道题,栈长在最近的面试过程中,却经常遇到很多求职者说反,搞不清使用场景的情况。

String    StringBuffer    StringBuilder
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间 StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量 可变类,速度更快
不可变    可变   可变
 线程安全    线程不安全

StringBuffer是单线程的,因为里面的方法都是被synchronized修饰了。所以它线程安全,但是效率自然就降低。

多线程操作字符串建议使用StringBuffer。

StringBuilder不是单线程的,因为里面的方法没有被synchronized修饰了。所以它线程不安全,所以效率要更高。

单线程操作字符串建议使用StringBuilder

一、Java String 类——String字符串常量

    简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,这样不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

我们来看一下这张对String操作时内存变化的图:

      我们可以看到,初始String值为“hello”,然后在这个字符串后面加上新的字符串“world”,这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了“hello world”字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费。

      为了应对经常性的字符串相关的操作,就需要使用Java提供的其他两个操作字符串的类——StringBuffer类和StringBuild类来对此种变化字符串进行处理。String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

二、 看看 StringBuffer 和 StringBuilder 的类结构吧:

 其实很简单,就是继承了一个抽象的字符串父类:AbstractStringBuilder。下面我们再来看看它们的三个区别。

区别1:线程安全

StringBuffer:线程安全,StringBuilder:线程不安全。因为 StringBuffer 的所有公开方法都是 synchronized 修饰的,而 StringBuilder 并没有 StringBuilder 修饰。

StringBuffer 代码片段:

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

区别2:缓冲区

StringBuffer 代码片段:

private transient char[] toStringCache;

@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

StringBuilder 代码片段:

@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

可以看出,StringBuffer 每次获取 toString 都会直接使用缓存区的 toStringCache 值来构造一个字符串。

而 StringBuilder 则每次都需要复制一次字符数组,再构造一个字符串。

所以,缓存冲这也是对 StringBuffer 的一个优化吧,不过 StringBuffer 的这个toString 方法仍然是同步的。

区别3:性能

既然 StringBuffer 是线程安全的,它的所有公开方法都是同步的,StringBuilder 是没有对方法加锁同步的,所以毫无疑问,StringBuilder 的性能要远大于 StringBuffer。

总结

所以,StringBuffer 适用于用在多线程操作同一个 StringBuffer 的场景,如果是单线程场合 StringBuilder 更适合。

StringBuilder 和 StringBuffer 常用方法:

StringBuilder 和 StringBuffer 方法和功能完全一致,只是一个是早期版本(StringBuffer)是线程安全的,由于发现利用多线程堆同一String数据操作的情况是很少的,为了提高效率idk1.5以后有StringBuilder 类。意思是多线程操作同一字符串的时候用StringBuffer 安全,现在一般用StringBuilder

StringBuffer是一个容器,长度可变,可以直接操作字符串,用toString方法变为字符串 

1.存储
        1)append(); //将指定数据加在容器末尾,返回值也是StringBuffer
        eg:
        StringBuffer sb = new StringBuffer(//可以加str);
        StringBuffer sb1=ab.append(数据) //数据可以任何基本数据类型
    注:此时sb == sb1他们是同一对象,意思是可以不用新建sb1直接 sb.append(数据) 使用时之后接使用sb

       2)insert();// 插入
       sb.insert(index ,数据);

2.删除
        sb.delete(start ,end);  //删除start到end的字符内容
        //注意:这里的所有包含index的操作都是含头不含尾的
        sb.deleteCharAt(index);//删除指定位置的字符
         //清空StringBuffer缓冲区
        sb=new StringBuffer();
        sb.delete(0,sb.length());

3.获取
    char c = sb.charAt(index);//获取index上的字符
    int i = sb.indexOf(char)://获取char字符出现的第一次位置
    //与 String 中的获取方法一致参考前面

4.修改    String类中无次操作方法
    sb =sb.replace(start,end,string)//将从start开始到end的字符串替换为string;
    sb.setCharAr(index ,char);//将index位置的字符变为新的char

5.反转  sb.reverse();//将sb倒序

6. getChars(int srcBegin,int srcEnd,char[] ch,int chBegin)
   //将StringBuffer缓冲区中的指定数据存储到指定数组中

  • 6
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值