String、StringBuffer与StringBuilder之间区别

 最近学习到StringBuffer,心中有好些疑问,搜索了一些关于String,StringBuffer,StringBuilder的东西,现在整理一下。

关于这三个类在字符串处理中的位置不言而喻,那么他们到底有什么优缺点,到底什么时候该用谁呢?下面我们从以下几点说明一下

  1.三者在执行速度方面的比较:StringBuilder >  StringBuffer  >  String

  2.String <(StringBuffer,StringBuilder)的原因

    String:字符串常量

    StringBuffer:字符创变量

    StringBuilder:字符创变量

    从上面的名字可以看到,String是“字符创常量”,也就是不可改变的对象。对于这句话的理解你可能会产生这样一个疑问  ,比如这段代码:

1  String s  =   " abcd " ;
2  =  s + 1 ;
3  System.out.print(s); //  result : abcd1

 

       我们明明就是改变了String型的变量s的,为什么说是没有改变呢? 其实这是一种欺骗,JVM是这样解析这段代码的:首先创建对象s,赋予一个abcd,然后再创建一个新的对象s用来    执行第二行代码,也就是说我们之前对象s并没有变化,所以我们说String类型是不可改变的对象了,由于这种机制,每当用String操作字符串时,实际上是在不断的创建新的对象,而原来的对象就会变为垃圾被GC回收掉,可想而知这样执行效率会有多底。

     而StringBuffer与StringBuilder就不一样了,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,这样就不会像String一样创建一些而外的对象进行操作了,当然速度就快了。

  3.一个特殊的例子:

1  String str  =  “This is only a”  +  “ simple”  +  “ test”;
3  StringBuffer builder  =   new  StringBuilder(“This is only a”).append(“ simple”).append(“ test”);

 

  

    你会很惊讶的发现,生成str对象的速度简直太快了,而这个时候StringBuffer居然速度上根本一点都不占优势。其实这是JVM的一个把戏,实际上:

    String str = “This is only a” + “ simple” + “test”;

    其实就是:

    String str = “This is only a simple test”;

    所以不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的String对象的话,速度就没那么快了,譬如:

    String str2 = “This is only a”;

    String str3 = “ simple”;

    String str4 = “ test”;

    String str1 = str2 +str3 + str4;

    这时候JVM会规规矩矩的按照原来的方式去做。

  4.StringBuilder与 StringBuffer

    StringBuilder:线程非安全的

    StringBuffer:线程安全的

    当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。

 

           对于三者使用的总结: 1.如果要操作少量的数据用 = String

                        2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

                        3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

 

Java中最常见也是应用最广泛的类就是String类。

String:Strings are constant; their values cannot be changed after they are created.

这是JDK对String的解释,意思是:String是常量,一旦创建后它的值不能被修改。

先看String对象是如何创建的:

String str1 = “abc”;

String str2 = new String(“abc”);

这是我们常见的两种形式。

第一种方式创建的字符串会放在栈里,更确切的是常量池中,常量池就是用来保存在编译阶段确定好了大小的数据,一般我们定义的int等基本数据类型就保存在这里。其具体的一个流程就是,编译器首先检查常量池,看看有没有一个“abc”,如果没有则创建。如果有的话,则则直接把str1指向那个位置。

第二种创建字符串的方法是通过new关键字,还是java的内存分配,java会将new的对象放在堆中,这一部分对象是在运行时创建的对象。所以我们每一次new的时候,都会创建不同的对象,即便是堆中已经有了一个一模一样的。

下面的程序将验证上面的说法。

1 String str1 = "abc";
2 String str2 = new String("abc");

4 String str3 = "abc";
5 String str4 = new String("abc");

7 System.out.println(str1==str2);//false
8    
9 System.out.println(str1 == str3);//true
10 System.out.println(str2 == str4);//false
11 // When the intern method is invoked, if the pool already contains a
12 // string equal to this String object as determined by the
13 // equals(Object) method, then the string from the pool is returned.
14 // Otherwise, this String object is added to the pool and a reference to
15 // this String object is returned.
16 str2 = str2.intern();
17 System.out.println(str1==str2);//true
18 
19 false
20 true
21 false
22 true

以上程序中用两种方式创建的4个对象,”==”比较的是地址,从结果可以看到str1和str3相同,指向同一个对象。而str2和str4比较返回结果是false,说明str2和str4指向的不是同一个对象。

(上面用到了一个比较少见的方法:intern。在str2调用了intern方法后对str1和str2进行比较返回true,可以从代码注释中看明白,intern方法返回常量池中内容和该对象相同的对象,如果常量池中不存在,则将该对象加入到常量池中。)

String对象是不变的,那为什么可以进行str+=”abc”这样的操作?其实类似这样的操作是新生成了一个String对象,包含str和abc连接后的字符串

1 package test;

3 public class StringTest {
4public static void main(String[] args) {
5    String str1 = "abc";
6    str1 += "123";
7}
8 }

从编译之后的class可以看出编译器自动引入了StringBuilder类,通过它的初始化方法创建了StringBuilder对象,通过append方法添加了内容,调用toString返回连接后的对象。以上内容证明了String对象是不可变的,连接操作实际是返回了新的对象。如果是循环多次进行连接,将不断的创建StringBuilder对象,append新内容,toString成String对象。这就带来了String类处理字符串更改操作的效率问题。


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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值