String、StringBuffer与StringBulider之间区别

java中String、StringBuffer、StringBulider是经常要用到的字符串类,那么它们之间到底有什么不同?以及它们的应用场景?

String字符串常量

String 简介

String 类是不可变类,所以String本身的值是不能改变的,任何对String的操作都会引起新的String对象的产生.去看看String类的具体实现你就会发现,用来保存字符串的数组用final修饰:
下面的代码段是String类的部分实现.

   private final char value[];  //保存字符串的数组.

如何证明String对象本身的值不可变?
String s="abcd";
s=s+1;
System.out.println(s);  //result:abcd1;

这段代码大家一定已经用烂了,从结果来看,我们明明改变了String类型的变量s,为什么说String对象是不可变的呢,其实这是一种欺骗,JVM是这样解析这段代码的:首先创建对象s,赋予abcd,然后再创建一个新的对象s来执行第二行的代码,也就是说我们之前的对象s并没有改变.所以说String类型是不可变的对象了,由于这种机制,每当用String操作字符串时,实际上是不断的创建新的对象,所以效率会比较高,原来的对象会被GC回收掉.看下面这段代码:

String a="aaaaaa";  
System.out.println(a.replace('a','b'); //result:bbbbbb  
System.out.println(a);    //result:aaaaaa

从结果可以看出,执行a.repalce(‘a’,’b’);并没有在a对象上操作,而是创建了一个新的对象. 因为最后a的值还是aaaaaa.

StringBuffer(字符串变量)

StringBuffer简介

操作StringBuffer类型字符串时,每次结果都会对StringBuffer对象本身进行操作,而不是生成新的对象,而改变对象引用,所以一般情况推荐使用StringBuffer,特别是字符串对象经常改变的情况下.

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    char[] value; //保存字符串的字符数组.

上面是StringBuffer的部分实现,大家可以看到,它继承了AbstractStringBuilder,用可变的数组保存要操作的字符串.

怎样证明StringBuffer类型的字符串是在自身上操作?
StringBuffer b=new StringBuffer("aaaaaa");  
System.out.println(b.replace(0,6,"bbbbbb");   //result:bbbbbb
System.out.println(b); result:bbbbbb; 

从结果可以看出,执行b.replace(0,6,”bbbbbb”,b的内容也变成了bbbbbb,说明,字符串的替换是在b对象本身上进行的.

线程安全的StringBuffer

StringBuffer 对方法加了同步锁,或对调用的方法加了同步锁,所以是线程安全的.部分源码如下:

@Override
    public synchronized int length() {
        return count;
    }

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

StringBuilder(字符串变量) 

StringBuilder简介

操作StringBuilder类型的字符串时,每次结果也都是在对象本身进行操作,不会产生新的对象.部分源码如下:

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
    abstract class AbstractStringBuilder implements Appendable, CharSequence {
    char[] value;保存字符串的字符数组.

从上面的可以看出.它继承了AbstractStringBuilder,用可变的数组保存要操作的字符串.

如何证明StringBulider是在对象本身进行操作?

StringBuilder b=new StringBuffer("aaaaaa");  
System.out.println(b.replace(0,6,"bbbbbb");   //result:bbbbbb

从结果可以看出,执行b.replace(0,6,”bbbbbb”,b的内容也变成了bbbbbb,说明,字符串的替换是在b对象本身上进行的.

非线程安全StringBuilder

部分源码如下:

 @Override
    public int length() {
        return count;
    }
public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

StringBuildler与StringBuffer共同点 

  • StringBuilder与StringBuffer有公共父类AbstractStringBuilder(抽象类)。
  • 抽象类与接口的其中一个区别是:抽象类中可以定义一些子类的公共方法,子类只需要增加新的功能,不需要重复写已经存在的方法;而接口中只是对方法的申明和常量的定义。
  • StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder中的公共方法,如super.append(…)。只是StringBuffer会在方法上加synchronized关键字,进行同步。
String,StringBuffer,StringBulider效率问题
  • 对String类型的字符串操作每次都要构造新的字符串,效率最慢(用一种情况例外).
  • StringBuffer,StringBuilder类型的字符串的操作都在自身上操作,减少了系统创建对象的开销,但是Stringbuffer是线程安全的,在并发操作中,对此类型的字符串的操作都是安全的,所以,相对于StringBuilder,由于线程安全要进行加锁—>修改—->释放锁的逻辑,效率比较低. 所以在单线程下优先选择StringBulider.
  • 速度从慢到快:String

应用场景

  • String 一般用于操作少量的数据.
  • 单线程操作字符串缓冲区下操作大量数据StringBuilder;
  • 多线程操作字符串缓冲区下操作大量数据StringBuffer;

测试实例

下面是一个String,StringBuffer,StringBuilder速度测试代码: 
方法是分别用String,StringBuffer,StringBulider连接2000000个字符串,看其执行时间,由于String特别慢,而StringBulider特别快,所以String连接了20000个,而只有在大量连接操作中,StringBuilder和StringBuffer的效率草拟体现出来,所以StringBuilder和StringBuffer都连接的是2000000个字符串. 最后测试了StringBuffer和StringBulider的赋值操作:
代码如下:

package thread;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * Created by yang on 16-7-10.
 */

public class StringTest {

    public static String BASEINFO = "yang";
    public static final int COUNT = 2000000;

    /**
     * 执行一项String赋值测试
     */
    public static void doStringTest() {

        String str = new String(BASEINFO);
        long starttime = System.currentTimeMillis();
        for (int i = 0; i < COUNT/100; i++) {
            str = str + "xiyou";
        }
        long endtime = System.currentTimeMillis();
        System.out.println((endtime - starttime)
                + " millis has costed when used String.");
    }

    /**
     * 执行一项StringBuffer赋值测试
     */
    public static void doStringBufferTest() {

        StringBuffer sb = new StringBuffer(BASEINFO);
        long starttime = System.currentTimeMillis();
        for (int i = 0; i < COUNT; i++) {
            sb = sb.append("miss");
        }
        long endtime = System.currentTimeMillis();
        System.out.println((endtime - starttime)
                + " millis has costed when used StringBuffer.");
    }

    /**
     * 执行一项StringBuilder赋值测试
     */
    public static void doStringBuilderTest() {

        StringBuilder sb = new StringBuilder(BASEINFO);
        long starttime = System.currentTimeMillis();
        for (int i = 0; i < COUNT; i++) {
            sb = sb.append("miss");
        }
        long endtime = System.currentTimeMillis();
        System.out.println((endtime - starttime)
                + " millis has costed when used StringBuilder.");
    }

    /**
     * 测试StringBuffer遍历赋值结果
     *
     * @param mlist
     */
    public static void doStringBufferListTest(List<String> mlist) {
        StringBuffer sb = new StringBuffer();
        long starttime = System.currentTimeMillis();
        for (String string : mlist) {
            sb.append(string);
        }
        long endtime = System.currentTimeMillis();
        System.out.println(sb.toString() + "buffer cost:"
                + (endtime - starttime) + " millis");
    }

    /**
     * 测试StringBuilder迭代赋值结果
     *
     * @param mlist
     */
    public static void doStringBuilderListTest(List<String> mlist) {
        StringBuilder sb = new StringBuilder();
        long starttime = System.currentTimeMillis();
        for (Iterator<String> iterator = mlist.iterator(); iterator.hasNext();) {
            sb.append(iterator.next());
        }

        long endtime = System.currentTimeMillis();
        System.out.println(sb.toString() + "builder cost:"
                + (endtime - starttime) + " millis");
    }

    public static void main(String[] args) {
        doStringTest();
        doStringBufferTest();
        doStringBuilderTest();

        List<String> list = new ArrayList<String>();
        list.add(" I ");
        list.add(" like ");
        list.add(" xiyou ");
        list.add(" linux ");
        list.add(" xingqu ");
        list.add(" xiaozu ");
        list.add(" . ");

        doStringBufferListTest(list);
        doStringBuilderListTest(list);
    }

}

结果如下:

1779 millis has costed when used String. //连接了20000个字符串
79 millis has costed when used StringBuffer. //连接了2000000个字符串.
53 millis has costed when used StringBuilder. //连接了2000000个字符串.
I like xiyou linux xingqu xiaozu. buffer cost:1 millis //7次循环赋值操作
I like xiyou linux xingqu xiaozu. builder cost:0 millis//7次循环赋值操作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值