您的位置:首页 > 产品设计 > UI/UE

String、StringBuilder、StringBuffer

2016-02-22 18:00 453 查看
先进行一段测试代码:

<span style="font-size:14px;">	long startStr = System.currentTimeMillis();
String str = "";
for(int i = 0 ; i<100000 ; i++){
str += i;
}
long endStr = System.currentTimeMillis();
System.out.println("String循环用时:" + String.valueOf(endStr-startStr));
long startSbf = System.currentTimeMillis();
StringBuffer sbf = new StringBuffer();
for(int i = 0 ; i<100000 ; i++){
sbf.append(i);
}
long endSbf = System.currentTimeMillis();
System.out.println("StringBuffer循环用时:" + String.valueOf(endSbf-startSbf));
long startSbi = System.currentTimeMillis();
StringBuilder sbi = new StringBuilder();
for(int i = 0 ; i<100000 ; i++){
sbi.append(i);
}
long endSbi = System.currentTimeMillis();
System.out.println("StringBuilder循环用时:" + String.valueOf(endSbi-startSbi));</span>


输出结果:
<span style="font-size:14px;">String循环用时:28509
StringBuffer循环用时:21
StringBuilder循环用时:14</span>
对比一下发现在进行字符串多次拼接时String花费的时间远远大于StringBuffer和StringBuilder,StringBuilder花费时间最少。

类的定义:

1.
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];

/** Cache the hash code for the string */
private int hash; // Default to 0

/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
……
}


2.

public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{

/** use serialVersionUID from JDK 1.0.2 for interoperability */
static final long serialVersionUID = 3388685877147921107L;

/**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
}
……
}


3.
<pre class="java" name="code">public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{

/** use serialVersionUID for interoperability */
static final long serialVersionUID = 4383685877147921099L;

/**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
}
……
}




附:

abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;

/**
* The count is the number of characters used.
*/
int count;

/**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
}

/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
……
}
1.三个类都被声明为了final,意味着三个类都不能被继承,并且它们的成员方法都默认为final方法,final意味着不能够修改,也就是说这些方法不能够被覆写。

2.上面列举出了各个类中所有的成员属性,从上面可以看出这些类其实是通过char数组来保存字符串的。

String、StringBuffer、StringBuilder的关系
从类的定义中可以看出StringBuffer与StringBuilder都继承了同一个父类,两个类中的方法大部分是相同的,String在处理字符串频繁拼接的时候效率慢,有StringBuffer类进行解决了,为什么还需要StringBuilder?

在文档注释中有这样的三句话:

String:@since JDK1.0

StringBuffer:@since JDK1.0

StringBuilder:@since 1.5

大致可以看出,StringBuilder出现的比较晚,目的是对StringBuffer进行简易替换以进一步提高效率,在提高效率的同时必然有部分功能是要舍弃的。

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

②StringBuffer线程安全的可变字符序列。可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。

在使用StringBuffer或是StringBuilder时用到的最多的方法是append和insert,执行效率也就体现在这两个方法上,两个类中方法的对比:

java.lang.StringBuffer#publicsynchronized
StringBuffer append……
java.lang.StringBuilder#public
StringBuilder append……
可以发现在StringBuffer的方法声明中多了synchronized修饰,也就是该方法是线程安全的,且在StringBuffer中多数方法是线程安全的,但是在StringBuilder中没有对线程进行考虑,也就是StringBuilder更快的原因所在。
而String慢又慢在什么地方呢?
都知道String是一个常量,存储在内存中一个叫字符串缓冲池的区域中,一经生成,不可改变。看下面的一段代码:

<span style="font-size:14px;">String str1 = "abc";
String str2 = str1;
str1 +="d";
System.out.println(str1);//abcd
System.out.println(str1==str2);//false
System.out.println(str2);//abc
StringBuffer sbf1 = new StringBuffer("abc");
StringBuffer sbf2 = sbf1;
sbf1.append("d");
System.out.println(sbf1==sbf2);//true
System.out.println(sbf2);//abcd
StringBuilder sbi1 = new StringBuilder("abc");
StringBuilder sbi2 = sbi1;
sbi1.append("d");
System.out.println(sbi1==sbi2);//true
System.out.println(sbi2);//abcd</span>


能够看出:String在进行字符串拼接的时候原对象并没有改变,而是生成一个全新的对象并将引用赋值给变量,而StringBuffer和StringBuilder是在原对象上进行的操作。这也就解释了为什么String进行字符串频繁拼接效率低的原因。
但是StringBuilder就一定是最快的吗?
String str = "hel" + "lo" + "wor" + "ld" + "。";
StringBuffer sbf = new StringBuffer().append("hel").append("lo").append("wor").append("ld").append("。");
StringBuilder sbi = new StringBuilder().append("hel").append("lo").append("wor").append("ld").append("。");


执行上面三局代码的时候,效率显然是第一句快一些。对于少量的字符串直接相加,效率很高,因为在编译时便确定了它的值,是个常量。但是对于使用变量进行的字符串+操作,效率就不如StringBuffer和StringBuilder了。
总结:
1.String适用于少量字符串直接相加操作;
2.StringBuilder适用于不考虑线程的情况下的多字符串拼接操作,也是优先考虑的;
3.StringBuffer只有在考虑现车甘泉的情况下才使用;
4.执行大量字符串拼接操作时速度:String<StringBuffer<StringBuilder;
5.StringBuilder比StringBuffer快的原因是忽略了对线程安全的考虑,是StringBuffer的简易替换。

附录:StringBuffer与StringBuilder方法整理
1.构造方法,经常使用的是构造一个其中不带字符的对象,其初始容量都为 16 个字符。以及传入String字符串构造一个对象。
2.append(),拼接字符串;
3.insert(),插入字符串;
4.detelte(),删除字符串;
以及一些类似于String类的方法、获取容量、反转操作等方法。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: