Java中的String、StringBuilder,StringBuffer简析

来源:互联网 发布:已连接,但无法访问网络 编辑:程序博客网 时间:2024/06/05 07:19

JAVA中用于处理字符串常用的有三个类:java.lang.String、java.lang.StringBuffer、java.lang.StringBuilder,这三者的共同之处都是final类,不允许被继承,这主要是从性能和安全性上考虑的,因为这几个类都是经常被使用着的,且考虑到防止其中的参数被修改影响到其它的应用。StringBuffer与StringBuilder两个基本上差不多,只是StringBuffer是线程安全,可以不需要额外的同步用于多线程中;StringBuilder是非同步,运行于多线程中就需要使用着单独同步处理,但是速度就比StringBuffer快多了;二者之间的共同点都可以通过append、insert进行字符串的操作。

String实现了三个接口:Serializable、Comparable<String>、CharSequence,而StringBuffer及StringBuilder只实现了两个接口Serializable、CharSequence,相比之下String的实例可以通过compareTo方法进行比较,而其它两个就不可以。

StringBuffer线程安全的可变字符序列。只要发生有关源序列(如在源序列中添加或插入)的操作,该类就只在执行此操作的字符串缓冲区上而不是在源上实现同步。从 JDK 5 开始,为该类补充了一个单个线程使用的等价类,即 StringBuilder。与该类相比,通常应该优先使用 StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快。

StringBuilder一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。

详细出处参考http://wenku.baidu.com/view/5d696e3e5727a5e9856a6123.html

1. String 类,String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。 String a = "a"; //假设a指向地址0x0001 a = "b";//重新赋值后a指向地址0x0002,但0x0001地址中保存的"a"依旧存在,但已经不再是a所指向的,a 已经指向了其它地址。 因此String的操作都是改变赋值地址而不是改变值操作。

2. StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。 每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。

StringBuffer buf=new StringBuffer(); //分配长16字节的字符缓冲区 StringBuffer buf=new StringBuffer(512); //分配长512字节的字符缓冲区 StringBuffer buf=new StringBuffer("this is a test")//在缓冲区中存放了字符串,并在后面预留了16字节的空缓冲区。

3.StringBuilder,StringBuffer和StringBuilder类功能基本相似,主要区别在于StringBuffer类的方法是多线程、安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。对于经常要改变值的字符串应该使用StringBuffer和StringBuilder类。

4.线程安全: StringBuffer 线程安全; StringBuilder 线程不安全

5.速度:一般情况下,速度从快到慢:StringBuilder>StringBuffer>String,这种比较是相对的,不是绝对的。

6.总结:(1)如果要操作少量的数据用String (2)单线程操作字符串缓冲区下操作大量数据用StringBuilder (3)多线程操作字符串缓冲区下操作大量数据StringBuffer

详细出处参考:http://www.jb51.net/article/33398.htm

 来看看 StringBuffer类源码定义:

复制代码
public final class StringBuffer    extends AbstractStringBuilder    implements java.io.Serializable, CharSequence{    public StringBuffer() {    super(16);    }     public StringBuffer(int capacity) {    super(capacity);    }    ...
复制代码

然后,我们打开 StringBuilder源码定义:

复制代码
public final class StringBuilder    extends AbstractStringBuilder    implements java.io.Serializable, CharSequence{    public StringBuilder() {    super(16);    }    public StringBuilder(int capacity) {    super(capacity);    }    ...
复制代码

我们发现两者都继承了AbstractStringBuilder抽象类。且构造方法都调用父类实现。
我们接着看两者append方法实现,先看StringBuffer的:

复制代码
 public synchronized StringBuffer append(Object obj) {        super.append(String.valueOf(obj));        return this;    }    public synchronized StringBuffer append(String str) {        super.append(str);        return this;    }    //...
复制代码

再看StringBuilder的:

复制代码
    public StringBuilder append(Object obj) {        return append(String.valueOf(obj));    }    public StringBuilder append(String str) {        super.append(str);        return this;    }    //...
复制代码

对比上面两段源码 我们发现 StirngBuffer 和StringBuilder的 append实现都是调用父类实现的。唯一不同的是 StringBuffer是线程安全的,方法中多了synchronized ,而StringBuilder 是非线程安全的。

我们再看一下append的实现:

复制代码
    public AbstractStringBuilder append(Object obj) {        return append(String.valueOf(obj));    }        public AbstractStringBuilder append(String str) {        //对于str==null的        if (str == null) str = "null";        int len = str.length();        if (len == 0) return this;        //新的字符串长度        int newCount = count + len;        if (newCount > value.length)             //当新的字符串长度比原先数组长度大时,需要对char 数组扩容。               expandCapacity(newCount);        //将新添的数据追加到char类型数组中。         str.getChars(0, len, value, count);        count = newCount;        return this;    }        //数组扩容     void expandCapacity(int minimumCapacity) {        //先扩容成 (原先的长度+1)*2        int newCapacity = (value.length + 1) * 2;        //判断newCapacity值是否满足要求         //如果新的长度还是不够,则直接取值 minimumCapacity         if (newCapacity < 0) {           newCapacity = Integer.MAX_VALUE;        } else if (minimumCapacity > newCapacity) {           newCapacity = minimumCapacity;        }            char newValue[] = new char[newCapacity];        //将原先的数据拷贝到新的char 数组中。         System.arraycopy(value, 0, newValue, 0, count);        value = newValue;    }     public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {        if (srcBegin < 0) {            throw new StringIndexOutOfBoundsException(srcBegin);        }        if (srcEnd > count) {            throw new StringIndexOutOfBoundsException(srcEnd);        }        if (srcBegin > srcEnd) {            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);        }        System.arraycopy(value, offset + srcBegin, dst, dstBegin,             srcEnd - srcBegin);    }
原创粉丝点击