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

String优势与StringBuffer,StringBuider优势,还有存于不同区域存在的性能差别

2017-09-17 18:38 501 查看
String是一个不可变字符串,寄存值是一把好手,做不到改变值,若是要对字符串进行一直追加值,是做不到改变自身值的,只有不停的引用产生的新字符串对象。

                String b = new String("123");
long time1 = System.currentTimeMillis();

for (int i = 0; i < 10000; i++) {
b += i;
}
System.out.println(System.currentTimeMillis() - time1);

此速度为293毫秒,为什么会这样呢?

首先在堆中创建字符串对象存储了123,由b引用。第一次是字符串123+1=“1231”字符串;交给b引用。循环第二次,1231+“2”=“12312”;b引用12312字符串,以此类推,最后b引用123....9999。

提示:1:字符串与任何东西相加都是连接。2:字符串无法改变自身值,所以相加得到的是一个新字符串对象,被引用。

StringBuffer是一个可变字符串,对字符串进行追加是一把好手,能做到改变自身的值。

        StringBuffer b = new StringBuffer("123");
long time1 = System.currentTimeMillis();

for (int i = 0; i < 10000; i++) {
b.append(i);
}
System.out.println(System.currentTimeMillis() - time1);

此速度为1毫秒,为啥这么快?

之前的字符串,它是在堆中创建字符串对象存储123,再说进一点就是字符串中char字符组存储[‘1’,‘2’,‘3’],第一次”123“+1时,也就是新建一个新char数组,存['1','2','3','1']交给b

而Stringbuffer是一来就创建一个长度为19的char数组,前三个存['1','2','3'.....],第一次b存储的值"123"追加1时,是在一开始申请好的数组中,从下标3存,也就是['1','2','3','1'.....],第二次“:['1','2','3',’1‘,‘2’.....]一直存到下标为18满了,

然后的操作就是,新new一个数组,长度为40交给b引用,b的地址发生改变,继续存存满了新建数组继续引用,

相对字符串来说,字符串是加一次就是一个新对象,而Stringbuffer是一次就是个数组对象,加满了继续申请更长的数组。虽然我们的长度是一致的都是"123....9999",但是我们new对象数量上差距特别大。

               

还有一种字符串追加i的写法

                long time1 = System.currentTimeMillis();

for (int i = 0; i < 10000; i++) {
String b = new String("123");
b+=i;
}
System.out.println(System.currentTimeMillis() - time1);

此速度是6,为啥你和我第一种写法差别又是这么大呢?

首先咋们先得到这两种写法最后一次引用的值把,第一种写法最后的值:"123....9999",第二种写法最后的值:"1239999",

这两个的差距是什么呢?第一中"123....999",在字符串中,前面的123,与后面的999中间的省略号的值是!~9998的值,什么意思呢?第一次是1230,第二次是12301,第三次是123012,第四次1230123,一直到123....9999。的累加

而第二个写法的值,第一次是1230,第二次是1231,第三次是1232,一直到1239999,的累加。有区别吗?你可别和我之前一样,认为,这种字符串对象是在常量池的,不过一个是全局一个是局部,怎么差别这么大。

它的原因不是因为一个是全局一个是局部。它们的对象确实在常量池或堆,



它们造成的差距是:第一种第一次,b引用的"123"+"0"="1230",b引用新字符串对象1230,第二次b引用新字符串对象12301,始终都是b在引用新字符串,一直到b="123....9998",b="123...9999".

看一下差距吧:

long time1 = System.currentTimeMillis();

String a = "1230123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999";

for(int i=0;i<10000;i++) {
a+=i;
}

System.out.println(System.currentTimeMillis() - time1);

速度在310毫秒起伏,以上数字是啥?嘿嘿,这就是"123....9999"可怕吧,

第二次,字符串少的情况下:

long time1 = System.currentTimeMillis();

String a = "4389546723904328946234786574238564327985432857432890654378296543789265437892657832";

for(int i=0;i<10000;i++) {
a+=i;
}

System.out.println(System.currentTimeMillis() - time1);

速度在280毫秒左右起伏。

不过上面的数字多和下面的数字小,看着速度差距不是特别大,但是想啊,从"123"~"123....9999"越到后面越大,越到后面越费时,循环次数越多,基本就不用等了。

回到刚刚的第二种,它避免了每一次都去引用上一次的值,每一次都是新字符串对象”123“,所以+"9999"也就是"1239999"而不是"123...9999"

下图为证



看吧,从b+=i,也就是b=b+1;b=”123“+”0“;b=”1230“+”1“;从b引用新字符串对象之前得到时间,引用完后马上减去时间,仅计算一次,一般就是存于0/1秒之间,

也就是在1万次以内,先新建对象然后b引用,b是有多少次是达到了一秒。276,肯定有偏差,仅供产考,不过也能说一秒一秒的速度浪费了


第二种,由于是在循环中new对象,每一次都是从”123“开始追加i,得到新字符串对象交给b,这一种少了上一中覆盖上一次一大串的值,斌且拿着这一大串值进行追加,这一种少了这两种拖后腿方式。

而Stringbuffer就不一样了,拿着数组,从后面追加,满了申请新数组,值导进去,继续追加,也不带覆盖值,也不带一直不停的引用,就是个往后追加,速度更快。

<
a845
p>

当然Stringbuffer还可以更加优化,就是这不是先是19个长度,后满了增加到了40个长度,你可以把这个满了new新数组这个时间给节约下来。直接指定Stringbuffer中的char数组长度有多长,就省得满了new新数组时间,能快个几毫秒左右。

下一个问题,String是不是能被Stringbuffer占领了?

Stringbuffer追加比String更占有绝对优势,论寄存值,String快得多。

               StringBuffer b;

long time1 = System.currentTimeMillis();

for (int i = 0; i < 1000000; i++) {

b = new StringBuffer("10");

}
System.out.println(System.currentTimeMillis() - time1);

//此Stringbuffer,42毫秒

String b;

long time1 = System.currentTimeMillis();

for (int i = 0; i < 1000000; i++) {

b = new String("10");
}
System.out.println(System.currentTimeMillis() - time1);

//此String,7毫秒.如果不是在堆建,而是直接=”10“,速度2毫秒

所有Stringbuffer有追加的优势,String有寄存值的优势,各有各的优势。而且String是存在常量池优化嘛。

Stringbuffer线程安全,Sringbuider非线程安全,线程后面会讲解。

Stringbuffer,Stringbuider由于是可变字符串,那即可对数组下标进行操作,除了追加值,可以根据传入下标,插入值,删除值,还有个方法reverse ()可以将Stringbuffer内容反转过来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: