[转帖]String,StringBuffer,StringBuild的区别_Tomcat, WebLogic及J2EE讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Tomcat, WebLogic及J2EE讨论区 »
总帖数
4
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 11639 | 回复: 3   主题: [转帖]String,StringBuffer,StringBuild的区别        下一篇 
    本主题由 zhou 于 2012-12-3 10:56:08 置为精华
mengyuanye
注册用户
等级:少校
经验:1413
发帖:108
精华:7
注册:2012-11-14
状态:离线
发送短消息息给mengyuanye 加好友    发送短消息息给mengyuanye 发消息
发表于: IP:您无权察看 2012-11-21 10:46:26 | [全部帖] [楼主帖] 楼主

1. String对象内容是不可改变的,StringBuffer是可以改变的,并且高效; 
2. String

String a = "123";
a = a + "456";


上面两句,虽然a的值最终改变了,但是实际上在编译的时候,第一句a是一个对象,被分配了一个地址,第二句执行时,原来的a被释放,然后重新分配。
a 原本指向一 String object instance ("123"), a + "456" 会造出另一新的 String object instance ("123456"), 然后 a 再指向这新的 String instance. 
3. StringBuffer

StringBuffer b = new StringBuffer("asd");
b.append("fgh");


在这个过程中,只存在b这么一个对象,b 一直都指向一个 StringBuffer instance. append 也只是改变此 instance 的內容而已. 
看看以下代码:
将26个英文字母重复加了5000次,

 String tempstr = "abcdefghijklmnopqrstuvwxyz";
int times = 5000;
long lstart1=System.currentTimeMillis();
String str ="";
for(int i=0;i<times;i++)
{
      str+=tempstr;
}
long lend1=System.currentTimeMillis();
long time = (lend1-lstart1);
System.out.println(time);


可惜我的计算机不是超级计算机,得到的结果每次不一定一样一般为 154735 左右。
也就是154秒。
我们再看看以下代码

 String tempstr = "abcdefghijklmnopqrstuvwxyz";
int times = 5000;
long lstart2=System.currentTimeMillis();
StringBuffer sb =new StringBuffer();
for(int i=0;i<times;i++)
{
      sb.append(tempstr);
}
long lend2=System.currentTimeMillis();
long time2 = (lend2-lstart2);
System.out.println(time2);


得到的结果为 16 有时还是 0
所以结论很明显,StringBuffer 的速度几乎是String 上万倍。当然这个数据不是很准确。因为循环的次数在100000次的时候,差异更大。不信你试试。
下一次我将解释为什么StringBuffer 的效率比String 高这么多。
String与StringBuffer的区别?
如果你在网上一搜,会有非常多的答案,其中最多的就是String是不可变而StringBuffer是可变的,但是这可变与不可变究竟是什么意思呢?如果你能用IDE进行debug的话,你就会发现,String实例化以后所有的属性都是final的,而StringBuffer确不是,这就是可变与不可变。下面引用SCJP的试题来解释一下这个例子:
java 代码

 1 public class Test {
      2 public static void stringReplace (String text) {
            3 text = text.replace('j' , 'i');
      4 }
      5
      6 public static void bufferReplace (StringBuffer text) {
            7 text = text.append("C");
      8 }
      9
      10 public static void main (String args[]) {
            11 String textString = new String ("java");
            12 StringBuffer textBuffer = new StringBuffer ("java");
            13
            14 stringReplace (textString);
            15 bufferReplace (textBuffer);
            16
            17 System.out.println (textString + textBuffer);
      18 }
19 }


答案是 javajavaC
这是因为第七行text = text.append ("C"),append方法会改变text中的值,而text与textBuffer指向的地址是相同的。因此会打印javaC
再举个例子:

String a = "a"; //假设a指向地址0x0001
a = "b";//重新赋值后a指向地址0x0002,但0x0001地址中保存的"a"依旧存在,但已经不再是a所指向的。


因此String的操作都是改变赋值地址而不是改变值操作
一个String对象的长度是固定的,不能改变它的内容,或者是附加新的字符至String对象中。您也许会使用+来串联字符串以达到附加新字符或字符串的目的,但+会产生一个新的String实例。如果程序对这种附加字符串的需求很频繁,并不建议使用+来进行字符串的串联。在面向对象程序设计中,最好是能重复运用已生成的对象,对象的生成需要内存空间与时间,不断地产生String实例是一个没有效率的行为。 
J2SE 5.0提供java.lang.StringBuilder类,使用这个类所产生的对象默认会有16个字符的长度,您也可以自行指定初始长度。如果附加的字符超出可容纳的长度,则StringBuilder对象会自动增加长度以容纳被附加的字符。如果有频繁作字符串附加的需求,使用StringBuilder会让程序的效率大大提高。通过下面的简单测试程序就可以知道效能差距有多大。 
ü 范例6.5 AppendStringTest.java 

 public class AppendStringTest {
      public static void main(String[] args) {
            String text = " ";
            long beginTime = System.currentTimeMillis();
            for(int i = 0; i < 10000; i++)
            text = text + i;
            long endTime = System.currentTimeMillis();
            System.out.println( "执行时间: " + (endTime - beginTime));
            StringBuilder builder = new StringBuilder( " ");
            beginTime = System.currentTimeMillis();
            for(int i = 0; i < 10000; i++)
            builder.append(String.valueOf(i));
            endTime = System.currentTimeMillis();
            System.out.println( "执行时间: " + (endTime - beginTime));
      }
}


在范例6.5中首先使用+来串联字符串,使用System.currentTimeMillis()取得for循环执行前、后的系统时间,这样就可以得知for循环执行了多久。以下是我的计算机上的测试数据: 
执行时间:4641 
执行时间:16 
可以看到执行的时间差距很大,这说明了使用+串联字符串所带来的负担。如果有经常作附加字符串的需求,建议使用StringBuilder。事实上就范例6.5来说,第二个for循环执行时间还可以更短,因为append()也可以接受基本数据类型,所以不必特地使用String.valueOf()方法从int取得String。改为以下的方式,执行时间可以大幅缩短: 

 for(int i = 0; i < 10000; i++)
builder.append(i);


使用StringBuilder最后若要输出字符串结果,可以用toString()方法。可以使用length()方法得知目前对象中的字符长度,而capacity()可返回该对象目前可容纳的字符容量。另外,StringBuilder还有像insert()方法可以将字符插入指定的位置,如果该位置以后有字符,则将所有的字符往后移;deleteChar()方法可以删除指定位置的字符,而reserve()方法可以反转字符串。详细的使用可以查询java.lang.StringBuilder的API文件说明。 
StringBuilder是J2SE 5.0才新增的类,在J2SE 5.0之前的版本若有相同的需求,则使用java.lang.StringBuffer。事实上,StringBuilder被设计为与StringBuffer具有相同的操作接口。在单机非多线程(Multithread)的情况下使用StringBuilder会有较好的效率,因为StringBuilder没有处理同步(Synchronized)问题。StringBuffer则会处理同步问题,如果StringBuilder会在多线程下被操作,则要改用StringBuffer,让对象自行管理同步问题。




赞(0)    操作        顶端 
hei_nihao
注册用户
等级:少校
经验:1279
发帖:19
精华:0
注册:2015-4-17
状态:离线
发送短消息息给hei_nihao 加好友    发送短消息息给hei_nihao 发消息
发表于: IP:您无权察看 2015-4-21 9:31:43 | [全部帖] [楼主帖] 2  楼

转了 北京联动北方科技有限公司



赞(0)    操作        顶端