String是咱們常常用到的一個類型,其實有時候以爲寫程序就是在反覆的操做字符串,這是C的特色,在java中,jdk很好的封裝了關於字符串的操做。今天主要講的是三個類String 、StringBuffer 、 StringBuilder .這三個類基本上知足了咱們在不一樣情景下使用字符串的需求。java
先說,第一個String。面試
JDK的解釋是 「Strings are constant; their values cannot be changed after they are created」也就是說String對象一旦被建立就是固定不變的了(你必定有問題,但請先等一等,耐心讀下去),這樣的一點好處就是能夠多線程之間訪問,由於只讀不寫。安全
通常狀況下咱們如下面兩種方式建立一個String對象多線程
兩種方式是有區別的,這和java的內存管理有關,前面已經說過,string建立以後是不可變的,因此按照第一種方式建立的字符串會放在棧裏,更確切的是常量池中,常量池就是用來保存在編譯階段肯定好了大小的數據,通常咱們定義的int等基本數據類型就保存在這裏。app
其具體的一個流程就是,編譯器首先檢查常量池,看看有沒有一個「string」,若是沒有則建立。若是有的話,則則直接把str1指向那個位置。測試
第二種建立字符串的方法是經過new關鍵字,仍是java的內存分配,java會將new的對象放在堆中,這一部分對象是在運行時建立的對象。因此咱們每一次new的時候,都會建立不一樣的對象,即使是堆中已經有了一個如出一轍的。ui
寫一個小例子線程
String str1 = "string"; String str4 = "string"; String str2 = new String("string"); String str3 = new String("string"); /*用於測試兩種建立字符串方式的區別*/ System.out.println(str1 == str4); System.out.println(str2 == str3); System.out.println(str3 == str1); str3 = str3.intern(); //一個不常見的方法 System.out.println(str3 == str1);
這個的運行結果是code
true //解釋:兩個字符串的內容徹底相同,於是指向常量池中的同一個區域對象
false //解釋:每一次new都會建立一個新的對象
false // 解釋: 注意==比較的是地址,不只僅是內容
true //介紹一下intern方法,這個方法會返回一個字符串在常量池中的一個地址,若是常量池中有與str3內容相同的string則返回那個地址,若是沒有,則在常量池中建立一個string後再返回。實際上,str3如今指向了str1的地址。
這就是讓人糾結的string了,如今你能夠說話了。。。不少人有這樣的疑問就是既然string是不變的,那麼爲何str1 + "some"是合法的,其實,每次對string進行修改,都會建立一個新的對象。
因此若是須要對一個字符串不斷的修改的話,效率是很是的低的,由於堆的好處是能夠動態的增長空間,劣勢就是分配新的空間消耗是很大的,好比咱們看下面的測試。
long start = System.currentTimeMillis(); for(int i = 0; i < 50000; i++) { str1+= " "; } long end = System.currentTimeMillis(); System.out.println("the run time is "+(end -start)+" ms");
個人機器上運行結果是the run time is 3538 ms 若是你把循環的次數後面再增長几個0就會更慢。由於每一次循環都在建立心的對象,那麼JDK如何解決這個問題?
下面就要說第二個類StringBuffer。
StringBuffer是一個線程安全的,就是多線程訪問的可靠保證,最重要的是他是可變的,也就是說咱們要操做一個常常變化的字符串,可使用這個類,基本的方法就是append(與string的concat方法對應)和insert方法,至於怎麼使用,就很少講了,你們能夠本身查看API。
StringBuilder sb = new StringBuilder("string builder"); StringBuffer sf = new StringBuffer("string buffer"); long start = System.currentTimeMillis(); for(int i = 0; i < 50000; i++) { //str1+= " "; sb.append(" "); } long end = System.currentTimeMillis(); System.out.println("the run time is "+(end -start)+" ms");
測試一下,此次只須要8ms,這就是效率。
那麼接下來,就要問StringBuilder是幹什麼的,其實這個纔是咱們嘗使用的,這個就是在jdk 1.5版本後面添加的新的類,前面說StringBuffer是線程同步的,那麼不少狀況下,咱們只是使用一個線程,那個同步勢必帶來一個效率的問題,StringBuilder就是StringBuffer的非線程同步的版本,兩者的方法差很少,只是一個線程安全(適用於多線程)一個沒有線程安全(適用於單線程)。
其實看了一下jdk源代碼就會發現,StringBuffer就是在各個方法上加上了關鍵字syncronized
以上就是對三個字符串類的一個總結,總之不要在這上面糾結。。。。。。不想介紹太多的方法,總以爲那樣會把一篇博客弄成API文檔同樣,並且還很是的繁瑣。都是些體會,但願有所幫助。起碼不要再糾結,尤爲是面試。。。。