首先貼出測試用例:

以下轉載:http://blog.sina.com.cn/s/blog_4ef2568301014xmd.html
1.首先介紹三個String對象比較的方法:
(1)equals:比較兩個String對象的值是否相等。例如:
輸出結果都為true。
(2)= =:比較兩個String對象的指向的記憶體位址是否相等。例如:
輸出結果都為false。
3.原理
要了解 java中String的運作方式,必須明确一點:String是一個非可變類(immutable)。什麼是非可變類呢?簡單說來,非可變類的執行個體是不能被修改的,每個執行個體中包含的資訊都必須在該執行個體建立的時候就提供出來,并且在對象的整個生存周期内固定不變。java為什麼要把String設計為非可變類呢?你可以問問 james Gosling :)。但是非可變類确實有着自身的優勢,如狀态單一,對象簡單,便于維護。其次,該類對象對象本質上是線程安全的,不要求同步。此外使用者可以共享非可變對象,甚至可以共享它們的内部資訊。(詳見 《Effective java》item 13)。String類在java中被大量運用,甚至在class檔案中都有其身影,是以将其設計為簡單輕便的非可變類是比較合适的。
(1)建立。
好了,知道String是非可變類以後,我們可以進一步了解String的構造方式了。建立一個Stirng對象,主要就有以下兩種方式:
雖然兩個語句都是傳回一個String對象的引用,但是jvm對兩者的處理方式是不一樣的。對于第一種,jvm會馬上在heap中建立一個String對象,然後将該對象的引用傳回給使用者。對于第二種,jvm首先會在内部維護的strings pool中通過String的 equels 方法查找是對象池中是否存放有該String對象,如果有,則傳回已有的String對象給使用者,而不會在heap中重新建立一個新的String對象;如果對象池中沒有該String對象,jvm則在heap中建立新的String對象,将其引用傳回給使用者,同時将該引用添加至strings pool中。注意:使用第一種方法建立對象時,jvm是不會主動把該對象放到strings pool裡面的,除非程式調用 String的intern方法。看下面的例子:
為什麼jvm可以這樣處理String對象呢?就是因為String的非可變性。既然所引用的對象一旦建立就永不更改,那麼多個引用共用一個對象時互不影響。
(2)串接(Concatenation)。
java程式員應該都知道濫用String的串接操作符是會影響程式的性能的。性能問題從何而來呢?歸根結底就是String類的非可變性。既然String對象都是非可變的,也就是對象一旦建立了就不能夠改變其内在狀态了,但是串接操作明顯是要增長字元串的,也就是要改變String的内部狀态,兩者出現了沖突。怎麼辦呢?要維護String的非可變性,隻好在串接完成後建立一個String 對象來表示新産生的字元串了。也就是說,每一次執行串接操作都會導緻新對象的産生,如果串接操作執行很頻繁,就會導緻大量對象的建立,性能問題也就随之而來了。
為了解決這個問題,jdk為String類提供了一個可變的配套類,StringBuffer。使用StringBuffer對象,由于該類是可變的,串接時僅僅時改變了内部資料結構,而不會建立新的對象,是以性能上有很大的提高。針對單線程,jdk 5.0還提供了StringBuilder類,在單線程環境下,由于不用考慮同步問題,使用該類使性能得到進一步的提高。
(3)String的長度
我們可以使用串接操作符得到一個長度更長的字元串,那麼,String對象最多能容納多少字元呢?檢視String的源代碼我們可以得知類String中是使用域 count 來記錄對象字元的數量,而count 的類型為 int,是以,我們可以推測最長的長度為 2^32,也就是4G。
不過,我們在編寫源代碼的時候,如果使用 Sting str = "aaaa";的形式定義一個字元串,那麼雙引号裡面的ASCII字元最多隻能有 65534 個。為什麼呢?因為在class檔案的規範中, CONSTANT_Utf8_info表中使用一個16位的無符号整數來記錄字元串的長度的,最多能表示 65536個位元組,而java class 檔案是使用一種變體UTF-8格式來存放字元的,null值使用兩個位元組來表示,是以隻剩下 65536- 2 = 65534個位元組。也正是變體UTF-8的原因,如果字元串中含有中文等非ASCII字元,那麼雙引号中字元的數量會更少(一個中文字元占用三個位元組)。如果超出這個數量,在編譯的時候編譯器會報錯。
(3)compareTo:比較兩個String對象的值是否相等。例如:
輸出結果都為0。(若輸出結果大于0表示str1大于str2)
2.String類的幾種初始化方法的差別
(1) String str1 = "hello quanjizhu";
首先到String pool中查找有沒有值為hello quanjizhu的對象,若有則讓str1直接指向此記憶體位址;若沒有則在記憶體堆中重新開辟空間給str1,并把hello quanjizhu加到String pool中。
(2)String str3 = new String("hello quanjizhu");
每次初始化都會重新在記憶體堆中開辟空間給新的對象,而不會到String pool中查找,更不會添加到String pool中。除非顯示的調用intern方法。
str3.interl();這時就會把hello quanjizhu加到String pool中。
(3)
String str1 = "hello quanjizhu";
String str2 ="hello" +"quanjizhu";
String str3 ="hello "+"quanjizhu";在編譯的時候會優化成String str3 = "hello quanjizhu";所有str1和str2指向的是同一記憶體位址。
(4)
String var = “quanjizhu“;
String str4 = “hello “+var;
System.out.println(str1= =str4)的結果是什麼呢?輸出結果是false,證明了String str4 = “hello “+var;
在記憶體堆中會重新配置設定空間,而不是讓str4指向var的位址。換用一種定義方法:str4 = (“hello “+var4).intern();intern()方法告訴編譯器将此結果放到String pool裡,是以,System.out.println(str1= =str4)輸出結構将是true;
唯有不斷學習方能改變!
-- <b>Ryan Miao</b>