三者都是对字符串的操作,要想知道String ,StringBuilder,StringBuffer的区别与联系我们要从源码看起:
String类
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/** The value is used for character storage. */
private final char value[];
String的底层是一个final修饰的Char数组,所以String的变量一旦定义以后,就不可更改。
StringBuffer类
1. 是一个字符缓冲区,其实就是一个容器。
2. 长度是可变的任意类型都行,任意数据都转为字符串存储。
3. 容器对象中提供很多对数据操作的功能,比如:增加,删除,查找修改。(append("str")、insert(2,"str"),delete(1,4))
4. 必须所有的数据最终变成字符串。
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
由源代码看出StringBuffer继承自 AbstractStringBuilder
StringBuilder类
功能和方法和StringBuffer相同,区别是StringBuffer同步,StringBuilder不同步
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);
}
由源代码看出StringBuilder同样继承自 AbstractStringBuilder
AbstractStringBuilder类
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
由源代码看出 AbstractStringBuilder中的数组Char[]并没有被final修饰,可以的出内容是可以改变的。所以StringBuffer和StringBuilder对象是可以改变的。
使用技巧:
1)如果要操作少量的数据用 String;
2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
3)单线程操作字符串缓冲区下操作大量数据 StringBuilder。
结论:
运行速度快慢为:StringBuilder > StringBuffer > String
为什么String最慢?:
String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。以下面一段代码为例:
1 String str="abc";
2 System.out.println(str);
3 str=str+"de";
4 System.out.println(str);
如果运行这段代码会发现先输出“abc”,然后又输出“abcde”,好像是str这个对象被更改了,其实,这只是一种假象罢了,JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。
为什么StringBuilder和StringBuffer比String快?:
对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。
1 String str="abc"+"de";
2 StringBuilder stringBuilder=new StringBuilder().append("abc").append("de");
3 System.out.println(str);
4 System.out.println(stringBuilder.toString());
这样输出结果也是“abcde”和“abcde”,但是String的速度却比StringBuilder的反应速度要快很多,这是因为第1行中的操作和
对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。
1 String str1="abc";
2 String str2="de";
3 String str=str1+str2;
上面的底层原理是:new StringBuffer().append("abc").append("de").toString()
为什么StringBuilder要比StringBuffer效率高?
方法只要加了synchronized同步,效率就是比不加synchronized的低,因为要对锁进行判断,出现线程等待,为了确保多线程下的安全,牺牲点效率也还行。
为什么StringBuffer是线程安全的?
如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。