[轉]整理關於java的String 類,equals函數和比較操作符的區別

初學 Java 有段時間了,感覺似乎開始入了門,有了點兒感覺但是發現很多困惑和疑問而且均來自於最基礎的知識折騰了一陣子又查了查書,終於對 String 這個特殊的對象有了點感悟大家先來看看一段奇怪的程序: 

  1. public class TestString {      
  2. public static void main(String[] args) {          
  3. String s1 = "Monday";          
  4. String s2 = "Monday";      
  5. }  
  6. }  

這個程序真是簡單啊!可是有什麼問題呢? 

1. 來自 String 的憂慮上面這段程序中,到底有幾個對象呢? 
可能很多人脫口而出:兩個,s1 和 s2爲什麼?String 是 final 類,它的值不可變。看起來似乎很有道理,那麼來檢測一下吧,稍微改動一下程序就可以看到結果了: 
  1. public class TestString {      
  2. public static void main(String[] args) {      
  3.     String s1 = "Monday";      
  4.     String s2 = "Monday";    
  5.      if (s1 == s2)        
  6.        System.out.println("s1 == s2");        
  7.     else        
  8.       System.out.println("s1 != s2");  
  9.     }  
  10. }  

呵呵,很多人都會說已經不止兩個對象了編譯並運行程序,輸出:s1 == s2啊! 
爲什麼 s1 == s2 ? 
== 分明是在說:s1 與 s2 引用同一個 String 對象 -- "Monday"! 

2. 千變萬化的 String再稍微改動一下程序,會有更奇怪的發現: 
  1. public class TestString {      
  2. public static void main(String[] args) {          
  3.     String s1 = "Monday";          
  4.     String s2 = new String("Monday");          
  5.     if (s1 == s2)              
  6.        System.out.println("s1 == s2");          
  7.     else              
  8.        System.out.println("s1 != s2");          
  9.     if (s1.equals(s2))              
  10.         System.out.println("s1 equals s2");        
  11.     else              
  12.         System.out.println("s1 not equals s2");      
  13. }  
  14. }  

 們將 s2 用 new 操作符創建程序輸出: 
s1 != s2s1 equals s2 
嗯,很明顯嘛s1 s2分別引用了兩個"Monday"String對象 
可是爲什麼兩段程序不一樣呢? 

3. 在 String 的游泳池中游泳哈哈,翻了翻書終於找到了答案: 
原 來,程序在運行的時候會創建一個字符串緩衝池當使用 s2 = "Monday" 這樣的表達是創建字符串的時候,程序首先會在這個String緩衝池中尋找相同值的對象,在第一個程序中,s1先被放到了池中,所以在s2被創建的時候, 程序找到了具有相同值的 s1將 s2 引用 s1 所引用的對象"Monday"第二段程序中,使用了 new 操作符,他明白的告訴程序:“ 要一個新的!不要舊的!”與是一個新 的"Monday"Sting對象被創建在內存中。他們的值相同,但是位置不同,一個在池中游泳一個在岸邊休息。哎呀,真是資源浪費,明明是一樣的非要分 開做什麼呢? 

4. 繼續潛水再次更改程序: 
  1. public class TestString {  
  2.     public static void main(String[] args) {  
  3.         String s1 = "Monday";  
  4.         String s2 = new String("Monday");  
  5.         s2 = s2.intern();  
  6.         if (s1 == s2)  
  7.             System.out.println("s1 == s2");  
  8.         else  
  9.             System.out.println("s1 != s2");  
  10.         if (s1.equals(s2))  
  11.             System.out.println("s1 equals s2");  
  12.         else  
  13.             System.out.println("s1 not equals s2");  
  14.     }  
  15. }  

這次加入:s2 = s2.intern(); 
哇!程序輸出:s1 == s2 s1 equals s2原來,程序新建了 s2 之後,又用intern()把他打翻在了池裏哈哈,這次 s2 和 s1 有引用了同樣的對象了 們成功的減少了內存的佔用

5. == 與 equals() 的爭鬥
String 是個對象,要對比兩個不同的String對象的值是否相同明顯的要用到 equals() 這個方法可是如果程序裏面有那麼多的String對象,有那麼多次的要用到 equals ,哦,天哪,真慢啊更好的辦法:把所有的String都intern()到緩衝池去吧最好在用到new的時候就進行這個操作String s2 = new String("Monday").intern();嗯,大家都在水池裏泡着了嗎?哈哈現在 可以無所顧忌的用 == 來比較 String 對象的值了真是爽啊,又快又方便!
 


String 啊 String ,讓 說你什麼好呢?你爲 們 Java 程序員帶來所有的困擾還不夠嗎? 
看看 String 這一次又怎麼鬧事兒吧 

1. 回顧一下壞脾氣的 String 老弟 
例程1:class Str { 
  1.     public static void main(String[] args) {  
  2.         String s = "Hi!";  
  3.         String t = "Hi!";  
  4.         if (s == t)  
  5.             System.out.println("equals");  
  6.         else  
  7.              System.out.println("not equals");  
  8.     }  
  9. }  

程序輸出什麼呢? 
如果看客們看過 的 《來自 String 的困惑》之一相信你很快會做出正確的判斷:程序輸出:equals 

2. 哦,天哪,它又在攪混水了 
例程2:class Str { 
  1.     public static void main(String[] args) {  
  2.         String s = "HELLO";  
  3.         String t = s.toUpperCase();  
  4.         if (s == t)  
  5.             System.out.println("equals");  
  6.         else  
  7.             System.out.println("not equals");  
  8.     }  
  9. }  

那麼這個程序有輸出什麼呢? 
慎重!再慎重!不要被 String 這個迷亂的傢伙所迷惑! 
它輸出:equalsWHY!!! 
把程序簡單的更改一下: 
  1. class Str2 {  
  2.     public static void main(String[] args) {  
  3.         String s = "Hello";  
  4.         String t = s.toUpperCase();  
  5.         if (s == t)  
  6.             System.out.println("equals");  
  7.         else  
  8.             System.out.println("not equals");  
  9.     }  
  10. }  

你可能會說:不是一樣嗎?不!千真萬確的,不一樣!這一次輸出: 
not equalsOh MyGOD!!! 
誰來教訓一下這個 String 啊!

3. 你瞭解你的馬嗎? 
“要馴服脫繮的野馬,就要了解它的秉性”牛仔們說道。 
你瞭解 String 嗎?解讀 String 的 API ,可以看到:toUpperCase() 和 toLowerCase() 方法返回一個新的String對象,它將原字符串表示字符串的大寫或小寫形勢;但是要注意:如果原字符串本身就是大寫形式或小寫形式,那麼返回原始對象。 這就是爲什麼第二個程序中 s 和 t 糾纏不清的緣故對待這個淘氣的、屢教不改的 String ,似乎沒有更好的辦法了讓 們解剖它,看看它到底有什麼結構吧: 
(1) charAt(int n) 返回字符串內n位置的字符,第一個字符位置爲0,最後一個字符的位置爲length()-1,訪問錯誤的位置會扔出一塊大磚 頭:StringIndexOutOfBoundsException 真夠大的 
(2) concat(String str) 在原對象之後連接一個 str ,但是返回一個新的 String 對象 
(3) EqualsIgnoreCase(String str) 忽略大小寫的 equals 方法這個方法的實質是首先調用靜態字符方法toUpperCase() 或者 toLowerCase() 將對比的兩個字符轉換,然後進行 == 運算 
(4) trim() 返回一個新的對象,它將原對象的開頭和結尾的空白字符切掉同樣的,如果結果與原對象沒有差別,則返回原對象 
(5) toString() String 類也有 toString() 方法嗎?真是一個有趣的問題,可是如果沒有它,你的 String 對象說不定真的不能用在System.out.println() 裏面啊小心,它返回對象自己String 類還有很多其他方法,掌握他們會帶來很多方便也會有很多困惑,所以堅持原則,是最關鍵的

4.  想買一匹更好的馬來購買更馴服溫和的 String 的小弟 StringBuffer 吧 
這時候會有人反對: 
它很好用,它效率很高,它怎麼能夠是小弟呢? 
很 簡單,它的交互功能要比 String 少,如果你要編輯字符串它並不方便,你會對它失望但這不意味着它不強大public final class String implements Serializable, Comparable, CharSequencepublic final class StringBuffer implements Serializable, CharSequence很明顯的,小弟少了一些東東,不過這不會干擾它的前途StringBuffer 不是由 String 繼承來的不過要注意兄弟它也是 final 啊,本是同根生看看他的方法吧,這麼多穩定可靠的方法,用起來比頑皮的 String 要有效率的多? Java 爲需要改變的字符串對象提供了獨立的 StringBuffer 類它的實例不可變(final),之所以要把他們分開是因爲,字符串的修改要求系統的開銷量增大,佔用更多的空間也更復雜,相信當有10000人擠在一個 狹小的游泳池裏游泳而岸邊又有10000人等待進入游泳池而焦急上火又有10000人在旁邊看熱鬧的時候,你這個 String 游泳池的管理員也會焦頭爛額在你無需改變字符串的情況下,簡單的 String 類就足夠你使喚的了,而當要頻繁的更改字符串的內容的時候,就要藉助於宰相肚裏能撐船的StringBuffer 了

5. 宰相肚裏能撐船 
(1) length() 與 capacity()String 中的 length() 返回字符串的長度兄弟 StringBuffer 也是如此,他們都由對象包含的字符長度決定capacity()呢? 
  1. public class TestCapacity {  
  2.     public static void main(String[] args){  
  3.      StringBuffer buf = new StringBuffer("it was the age of wisdom,");  
  4.        System.out.println("buf = " + buf);  
  5.         System.out.println("buf.length() = " + buf.length());  
  6.         System.out.println("buf.capacity() = " + buf.capacity());  
  7.         String str = buf.toString();  
  8.         System.out.println("str = " + str);  
  9.         System.out.println("str.length() = " + str.length());  
  10.         buf.append(" " + str.substring(0,18)).append("foolishness,");  
  11.         System.out.println("buf = " + buf);  
  12.         System.out.println("buf.length() = " + buf.length());  
  13.         System.out.println("buf.capacity() = " + buf.capacity());  
  14.        System.out.println("str = " + str);  
  15.    }  
  16. }  

程序輸出: 
buf = it was the age of wisdom.buf.length() = 25 
buf.capacity() = 41 
str = it was the age of wisdomstr.length() = 25 
buf = it was the age of wisdom, it was the age of foolishness, 
buf.length() = 56 
buf.capacity() = 84 
str = it was the age of wisdom,

可以看到,在內容更改之後,capacity也隨之改變了長度隨着向字符串添加字符而增加而容量只是在新的長度超過了現在的容量之後才增加 StringBuffer 的容量在操作系統需要的時候是自動改變的程序員們對capacity所能夠做的僅僅是可以在初始化 StringBuffer對象的時候。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章