www.baidu.com

          JavaCode--我愛你,芳兒

          JavaStudy--我愛你,芳兒

          Java語法總結(jié) - 字符串



          Java的String太特別了,也太常用了,所以重要。我初學(xué)Java就被它搞蒙了,太多混淆的概念了,比如它的不變性。所以必須深入機制地去理解它。


          1、String中的每個字符都是一個16位的Unicode字符,用Unicode很容易表達(dá)豐富的國際化字符集,比如很好的中文支持。甚至Java的標(biāo)識符都可以用漢字,但是沒人會用吧(只在一本清華的《Java2實用教程》看過)。

          2、判斷空字符串。根據(jù)需要自己選擇某個或者它們的組合
              if ( s == null )    //從引用的角度
              if ( s.length() == 0 )     //從長度判別
              if ( s.trim().length () == 0 )     //是否有多個空白字符
          trim()方法的作用是是移除前導(dǎo)和尾部的Unicode值小于'"u0020'的字符,并返回“修剪”好的字符串。這種方法很常用,比如需要用戶輸入用戶名,用戶不小心加了前導(dǎo)或者尾部空格,一個好的程序應(yīng)該知道用戶不是故意的,即使是故意的也應(yīng)該智能點地處理。
          判斷空串是很常用的操作,但是Java類庫直到1.6才提供了isEmpty()方法。當(dāng)且僅當(dāng) length() 為 0 時返回 true。

          3、未初始化、空串""與null。它們是不同的概念。對未初始化的對象操作會被編譯器擋在門外;null是一個特殊的初始化值,是一個不指向任何對象的引用,對引用為null的對象操作會在運行時拋出異常NullPointerException;而空串是長度為0的字符串,和別的字符串的唯一區(qū)別就是長度為0。
          例子:
              public class StringTest{
                  static String s1;
                  public static void main(String[] args) {
                      String s2;
                      String s3 = "";
                      System.out.print(s1.isEmpty());     //運行時異常
                      System.out.print(s2.isEmpty());     //編譯出錯
                      System.out.print(s3.isEmpty());     //ok!輸出true
                  }
              }

          4、String類的方法很多,在編寫相關(guān)代碼的時候看看JDK文檔時有好處的,要不然花了大量時間實現(xiàn)一個已經(jīng)存在的方法是很不值得的,因為編寫、測試、維護自己的代碼使項目的成本增加,利潤減少,嚴(yán)重的話會導(dǎo)致開不出工資……

          5、字符串的比較。
          Java不允許自定義操作符重載,因此字符串的比較要用compareTo() 或者 compareToIgnoreCase()。s1.compareTo(s2),返回值大于0則,則前者大;等于0,一般大;小于0,后者大。比較的依據(jù)是字符串中各個字符的Unicode值。

          6、toString()方法。
          Java的任何對象都有toString()方法,是從Object對象繼承而來的。它的作用就是讓對象在輸出時看起來更有意義,而不是奇怪的對象的內(nèi)存地址。對測試也是很有幫助的。

          7、String對象是不變的!可以變化的是String對象的引用。
          String name = "ray";
          name.concat("long");  //字符串連接
          System.out.println(name); //輸出name,ok,還是"ray"
          name = name.concat("long");  //把字符串對象連接的結(jié)果賦給了name引用
          System.out.println(name);  //輸出name,oh!,變成了"raylong"
          上述三條語句其實產(chǎn)生了3個String對象,"ray","long","raylong"。第2條語句確實產(chǎn)生了"raylong"字符串,但是沒有指定把該字符串的引用賦給誰,因此沒有改變name引用。第3條語句根據(jù)不變性,并沒有改變"ray",JVM創(chuàng)建了一個新的對象,把"ray","long"的連接賦給了name引用,因此引用變了,但是原對象沒變。

          8、String的不變性的機制顯然會在String常量內(nèi)有大量的冗余。如:"1" + "2" + "3" +......+ "n" 產(chǎn)生了n+(n+1)個String對象!因此Java為了更有效地使用內(nèi)存,JVM留出一塊特殊的內(nèi)存區(qū)域,被稱為“String常量池”。對String多么照顧啊!當(dāng)編譯器遇見String常量的時候,它檢查該池內(nèi)是否已經(jīng)存在相同的String常量。如果找到,就把新常量的引用指向現(xiàn)有的String,不創(chuàng)建任何新的String常量對象。

          那么就可能出現(xiàn)多個引用指向同一個String常量,會不會有別名的危險呢?No problem!String對象的不變性可以保證不會出現(xiàn)別名問題!這是String對象與普通對象的一點區(qū)別。

          乍看起來這是底層的機制,對我們編程沒什么影響。而且這種機制會大幅度提高String的效率,實際上卻不是這樣。為連接n個字符串使用字符串連接操作時,要消耗的時間是n的平方級!因為每兩個字符串連接,它們的內(nèi)容都要被復(fù)制。因此在處理大量的字符串連接時,而且要求性能時,我們不要用String,StringBuffer是更好的選擇。

          8、StringBuffer類。StringBuffer類是可變的,不會在字符串常量池中,而是在堆中,不會留下一大堆無用的對象。而且它可將字符串緩沖區(qū)安全地用于多個線程。每個StringBuffer對象都有一定的容量。只要StringBuffer對象所包含的字符序列的長度沒有超出此容量,就無需分配新的內(nèi)部緩沖區(qū)數(shù)組。如果內(nèi)部緩沖區(qū)溢出,則此容量自動增大。這個固定的容量是16個字符。我給這種算法起個名字叫“添飯算法”。先給你一滿碗飯,不夠了再給你一滿碗飯。
          例子:
              StringBuffer sb = new StringBuffer();    //初始容量為 16 個字符
              sb.append("1234");    //這是4個字符,那么16個字符的容量就足夠了,沒有溢出
              System.out.println(sb.length());    //輸出字符串長度是4
              System.out.println(sb.capacity());    //輸出該字符串緩沖區(qū)的容量是16

              sb.append("12345678901234567");        //這是17個字符,16個字符的容量不夠了,擴容為17+16個字符的容量
              System.out.println(sb.length());    //輸出字符串長度是17
              System.out.println(sb.capacity());    //輸出該字符串緩沖區(qū)的容量是34

              sb.append("890").reverse().insert(10,"-");    
              System.out.println(sb);        //輸出0987654321-09876543214321

          字符串的長度和字符緩沖區(qū)的容量是兩個概念,注意區(qū)別。
          還有串聯(lián)的方式看起來是不是很酷!用返回值連接起來可以實現(xiàn)這種簡潔和優(yōu)雅。

          10、StringBuilder類。 從J2SE 5.0 提供了StringBuilder類,它和StringBuffer類是孿生兄弟,很像。它存在的價值在于:對字符串操作的效率更高。不足的是線程安全無法保證,不保證同步。那么兩者性能到底差多少呢?很多!
          請參閱:http://book.csdn.net/bookfiles/135/1001354628.shtml
          實踐:
          單個線程的時候使用StringBuilder類,以提高效率,而且它的API和StringBuffer兼容,不需要額外的學(xué)習(xí)成本,物美價廉。多線程時使用StringBuffer,以保證安全。

          11、字符串的比較。
          下面這條可能會讓你暈,所以你可以選擇看或者不看。它不會對你的職業(yè)生涯造成任何影響。而且謹(jǐn)記一條,比較字符串要用equals()就ok了!一旦用了“==”就會出現(xiàn)很怪異的現(xiàn)象。之所以把這部分放在最后,是想節(jié)省大家的時間,因為這條又臭又長。推薦三種人:一、沒事閑著型。二、想深入地理解Java的字符串,即使明明知道學(xué)了也沒用。三、和我一樣愛好研究“茴”字有幾種寫法。

          還是那句老話,String太特殊了,以至于某些規(guī)則對String不起作用。個人感覺這種特殊性并不好。看例子:
          例子A:
              String str1 = "java";
              String str2 = "java";
              System.out.print(str1==str2);
          地球上有點Java基礎(chǔ)的人都知道會輸出false,因為==比較的是引用,equals比較的是內(nèi)容。不是我忽悠大家,你們可以在自己的機子上運行一下,結(jié)果是true!原因很簡單,String對象被放進(jìn)常量池里了,再次出現(xiàn)“java”字符串的時候,JVM很興奮地把str2的引用也指向了“java”對象,它認(rèn)為自己節(jié)省了內(nèi)存開銷。不難理解吧 呵呵
          例子B:
              String str1 = new String("java");
              String str2 = new String("java");
              System.out.print(str1==str2);
          看過上例的都學(xué)聰明了,這次肯定會輸出true!很不幸,JVM并沒有這么做,結(jié)果是false。原因很簡單,例子A中那種聲明的方式確實是在String常量池創(chuàng)建“java”對象,但是一旦看到new關(guān)鍵字,JVM會在堆中為String分配空間。兩者聲明方式貌合神離,這也是我把“如何創(chuàng)建字符串對象”放到后面來講的原因。大家要沉住氣,還有一個例子。
          例子C:
              String str1 = "java";
              String str2 = "blog";
              String s = str1+str2;
              System.out.print(s=="javablog");
          再看這個例子,很多同志不敢妄言是true還是false了吧。愛玩腦筋急轉(zhuǎn)彎的人會說是false吧……恭喜你,你會搶答了!把那個“吧”字去掉你就完全正確。原因很簡單,JVM確實會對型如String str1 = "java"; 的String對象放在字符串常量池里,但是它是在編譯時刻那么做的,而String s = str1+str2; 是在運行時刻才能知道(我們當(dāng)然一眼就看穿了,可是Java必須在運行時才知道的,人腦和電腦的結(jié)構(gòu)不同),也就是說str1+str2是在堆里創(chuàng)建的,s引用當(dāng)然不可能指向字符串常量池里的對象。沒崩潰的人繼續(xù)看例子D。
          例子D:
              String s1 = "java";
              String s2 = new String("java");
              System.out.print(s1.intern()==s2.intern());
          intern()是什么東東?反正結(jié)果是true。如果沒用過這個方法,而且訓(xùn)練有素的程序員會去看JDK文檔了。簡單點說就是用intern()方法就可以用“==”比較字符串的內(nèi)容了。在我看到intern()方法到底有什么用之前,我認(rèn)為它太多余了。其實我寫的這一條也很多余,intern()方法還存在諸多的問題,如效率、實現(xiàn)上的不統(tǒng)一……
          例子E:
              String str1 = "java";
              String str2 = new String("java");
              System.out.print(str1.equals(str2));
          無論在常量池還是堆中的對象,用equals()方法比較的就是內(nèi)容,就這么簡單!看完此條的人一定很后悔,但是在開始我勸你別看了……

          后記:用彪哥的話說“有意思嗎?”,確實沒勁。在寫這段的時候我也是思量再三,感覺自己像孔乙己炫耀“茴”字有幾種寫法。我查了一下茴 ,回,囘,囬,還有一種是“口”字里面有個“目”字,后面這四個都加上草字頭……


           

          芳兒寶貝.我愛你

          posted on 2007-12-08 14:34 wǒ愛伱--咾婆 閱讀(293) 評論(0)  編輯  收藏 所屬分類: JavaBaseFiles

          導(dǎo)航

          統(tǒng)計

          公告

          芳兒寶貝.我愛你


          黑客基地
          http://www.hackbase.com
          全球最大的黑客門戶網(wǎng)站


           最近在讀的書:

          常用鏈接

          留言簿(1)

          隨筆分類(37)

          JavaCode

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 额尔古纳市| 阿城市| 芮城县| 宽城| 临安市| 紫金县| 五峰| 杂多县| 遂昌县| 商丘市| 社旗县| 延庆县| 滦平县| 青海省| 邹平县| 兴安盟| 沈阳市| 凤冈县| 舞阳县| 通渭县| 呼玛县| 布尔津县| 当阳市| 浑源县| 贵州省| 乌恰县| 北票市| 南丹县| 昭苏县| 岢岚县| 绥中县| 常熟市| 东明县| 赣州市| 社旗县| 武川县| 民丰县| 蓬安县| 邛崃市| 崇阳县| 台南市|