String 总结
申明:
1.?首先String不屬于8種基本數(shù)據(jù)類型,String是一個對象。?因為對象的默認值是null,所以String
的默認值也是null;但它又是一種特殊的對象,有其它對象沒有的一些特性。?
2.?new?String()和new?String("")都是申明一個新的空字符串,是空串不是null;?
3.?String?str="kvill";?與?String?str=new?String?("kvill");的區(qū)別:
?
在這里,我們不談堆,也不談棧,只先簡單引入常量池這個簡單的概念。?
常量池(constant?pool)指的是在編譯期被確定,并被保存在已編譯的.class文件中的一些數(shù)據(jù)。它包括了關于類、方法、接口等中的常量,也包括字符串常量。?
例1:?
?
| String?s0="kvill";? |
結果為:?
| true? |
首先,我們要知結果為道Java會確保一個字符串常量只有一個拷貝。?
因為例子中的s0和s1中的"kvill"都是字符串常量,它們在編譯期就被確定了,所以s0==s1為true;而"kv"和"ill"也都是字符串常量,當一個字符串由多個字符串常量連接而成時,它自己肯定也是字符串常量,所以s2也同樣在編譯期就被解析為一個字符串常量,所以s2也是常量池中"kvill"的一個引用。?所以我們得出s0==s1==s2;?
注:用new?String()?創(chuàng)建的字符串不是常量,不能在編譯期就確定,所以new?String()?創(chuàng)建的字符串不放入常量池中,它們有自己的地址空間。在運行時創(chuàng)建的字符串具有獨立的內存地址,所以不引用自同一String對象。
例2:?
| String?s0="kvill";? |
結果為:
| false? |
?
例2中s0還是常量池中"kvill"的應用,s1因為無法在編譯期確定,所以是運行時創(chuàng)建的新對象"kvill"的引用,s2因為有后半部分new?String("ill")所以也無法在編譯期確定,所以也是一個新創(chuàng)建對象"kvill"的應用;明白了這些也就知道為何得出此結果了。?
4、String.intern():?
存在于.class文件中的常量池,在運行期被JVM裝載,并且可以擴充。String的intern()方法就是擴充常量池的一個方法;當調用?intern?方法時,如果池已經包含一個等于此?String?對象的字符串(該對象由?equals(Object)?方法確定),則返回池中的字符串。否則,將此?String?對象添加到池中,并且返回此?String?對象的引用。
例3:?
| String?s0=?"kvill";? |
結果為:?
| false? |
例4:?
| String?s1=new?String("kvill");? System.out.println(?s1+"?"+s2?); |
結果:?
| false? |
在這個類中我們沒有聲名一個"kvill"常量,所以常量池中一開始是沒有"kvill"的,當我們調用s1.intern()后就在常量池中新添加了一個"kvill"常量,原來不在常量池中的"kvill"仍然存在。
s1==s1.intern()為false說明原來的"kvill"仍然存在;?
s2現(xiàn)在為常量池中"kvill"的地址,所以有s2==s1.intern()為true。?
5、關于equals()和==:?
equals簡單來說就是比較兩字符串的Unicode序列是否相當,如果相等返回true;而==是比較兩字符串的地址是否相同,也就是是否是同一個字符串的引用。?對于字符串比較,一定要切記使用equals,勿用==.
?
String、StringBuffer與StringBuilder區(qū)別:
1、三者在執(zhí)行速度方面的比較:StringBuilder?>??StringBuffer??>??String
2、(StringBuffer、StringBuilder)在做字符串變動時將繼續(xù)使用原來的內存空間,不會重新分配內存。而String的長度或內容一旦變動,JVM將分配新的內存空間。
?
String?<(StringBuffer,StringBuilder)的原因:
String: 字符串常量
StringBuffer: 字符串變量
StringBuilder: 字符串變量
從上面的名字可以看到,String是"字符串常量",也就是不可改變的對象。對于這句話的理解你可能會產生這樣一個疑問,比如這段代碼:
| String?s?=?"abcd"; |
我們明明就是改變了String型的變量s的,為什么說是沒有改變呢??其實這是一種欺騙,JVM是這樣解析這段代碼的:首先創(chuàng)建對象s,賦予一個abcd,然后再創(chuàng)建一個新的對象s用來執(zhí)行第二行代碼,也就是說我們之前對象s并沒有變化,所以我們說String類型是不可改變的對象了,由于這種機制,每當用String操作字符串時,實際上是在不斷的創(chuàng)建新的對象,而原來的對象就會變?yōu)槔?#xff27;C回收掉,可想而知這樣執(zhí)行效率會有多底。
而StringBuffer與StringBuilder就不一樣了,他們是字符串變量,是可改變的對象,每當我們用它們對字符串做操作時,實際上是在一個對象上操作的,這樣就不會像String一樣創(chuàng)建一些額外的對象進行操作了,效率自然提升。
?
2、一個特殊的例子:
| String?str?=?"This?is?only?a"?+?"?simple"?+?"?test"; |
你會很驚訝的發(fā)現(xiàn),生成str對象的速度簡直太快了,而這個時候StringBuilder居然速度上根本一點都不占優(yōu)勢。其實這是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會規(guī)規(guī)矩矩的按照原來的方式去做。
3、StringBuilder與?StringBuffer
StringBuilder:線程非安全的
StringBuffer:線程安全的
當我們在字符串緩沖去被多個線程使用是,JVM不能保證StringBuilder的操作是安全的,雖然他的速度最快,但是可以保證StringBuffer是可以正確操作的。當然大多數(shù)情況下就是我們是在單線程下進行的操作,所以大多數(shù)情況下是建議用StringBuilder而不用StringBuffer的,就是速度的原因。
?
對于三者使用的總結:?
1、如果要操作少量的數(shù)據(jù)?=?String
2、單線程操作字符串緩沖區(qū)?下操作大量數(shù)據(jù)?=?StringBuilder
3、多線程操作字符串緩沖區(qū)?下操作大量數(shù)據(jù)?=?StringBuffer
轉載于:https://www.cnblogs.com/DswCnblog/archive/2012/11/01/2750172.html
總結
- 上一篇: Matrix calculus
- 下一篇: 改善java程序的建议