我的Blog我做主^_^

          走向一條通往JAVA的不歸路...

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            64 隨筆 :: 68 文章 :: 77 評論 :: 0 Trackbacks
          1、"abc"與new String("abc");
              經常會問到的面試題:String s = new String("abc");創建了幾個String Object?【如這里創建了多少對象? 和一道小小的面試題 】

              這個問題比較簡單,涉及的知識點包括:

          引用變量與對象的區別; 
          字符串文字"abc"是一個String對象; 
          文字池[pool of literal strings]和堆[heap]中的字符串對象。
              一、引用變量與對象:除了一些早期的Java書籍和現在的垃圾書籍,人們都可以從中比較清楚地學習到兩者的區別。A aa;語句聲明一個類A的引用變量aa[我常常稱之為句柄],而對象一般通過new創建。所以題目中s僅僅是一個引用變量,它不是對象。[ref 句柄、引用與對象]

              二、Java中所有的字符串文字[字符串常量]都是一個String的對象。有人[特別是C程序員]在一些場合喜歡把字符串"當作/看成"字符數組,這也沒有辦法,因為字符串與字符數組存在一些內在的聯系。事實上,它與字符數組是兩種完全不同的對象。

                  System.out.println("Hello".length());
                  char[] cc={'H','i'};
                  System.out.println(cc.length);

              三、字符串對象的創建:由于字符串對象的大量使用[它是一個對象,一般而言對象總是在heap分配內存],Java中為了節省內存空間和運行時間[如比較字符串時,==比equals()快],在編譯階段就把所有的字符串文字放到一個文字池[pool of literal strings]中,而運行時文字池成為常量池的一部分。文字池的好處,就是該池中所有相同的字符串常量被合并,只占用一個空間。我們知道,對兩個引用變量,使用==判斷它們的值[引用]是否相等,即指向同一個對象:

          String s1 = "abc" ;
          String s2 = "abc" ;
          if( s1 == s2 )
               System.out.println("s1,s2 refer to the same object");
          else
               System.out.println("trouble");

              這里的輸出顯示,兩個字符串文字保存為一個對象。就是說,上面的代碼只在pool中創建了一個String對象。

              現在看String s = new String("abc");語句,這里"abc"本身就是pool中的一個對象,而在運行時執行new String()時,將pool中的對象復制一份放到heap中,并且把heap中的這個對象的引用交給s持有。ok,這條語句就創建了2個String對象。

          String s1 = new String("abc") ;String s2 = new String("abc") ;if( s1 == s2 ){ //不會執行的語句}

              這時用==判斷就可知,雖然兩個對象的"內容"相同[equals()判斷],但兩個引用變量所持有的引用不同,

              BTW:上面的代碼創建了幾個String Object? [三個,pool中一個,heap中2個。]
              [Java2 認證考試學習指南 (第4版)( 英文版)p197-199有圖解。]


          2、字符串的+運算和字符串轉換
              字符串轉換和串接是很基礎的內容,因此我以為這個問題簡直就是送分題。事實上,我自己就答錯了。

          String str = new String("jf"); // jf是接分
          str = 1+2+str+3+4;
          一共創建了多少String的對象?[我開始的答案:5個。jf、new、3jf、3jf3、3jf34]

              首先看JLS的有關論述:

              一、字符串轉換的環境[JLS 5.4 String Conversion]

              字符串轉換環境僅僅指使用雙元的+運算符的情況,其中一個操作數是一個String對象。在這一特定情形下,另一操作數轉換成String,表達式的結果是這兩個String的串接。

              二、串接運算符[JLS 15.18.1 String Concatenation Operator + ]

              如果一個操作數/表達式是String類型,則另一個操作數在運行時轉換成一個String對象,并兩者串接。此時,任何類型都可以轉換成String。[這里,我漏掉了"3"和"4"]

          如果是基本數據類型,則如同首先轉換成其包裝類對象,如int x視為轉換成Integer(x)。 
          現在就全部統一到引用類型向String的轉換了。這種轉換如同[as if]調用該對象的無參數toString方法。[如果是null則轉換成"null"]。因為toString方法在Object中定義,故所有的類都有該方法,而且Boolean, Character, Integer, Long, Float, Double, and String改寫了該方法。 
          關于+是串接還是加法,由操作數決定。1+2+str+3+4 就很容易知道是"3jf34"。[BTW :在JLS的15.18.1.3中舉的一個jocular little example,真的很無趣。]
              下面的例子測試了改寫toString方法的情況.。

          class A{
              int i = 10;
              public static void main(String []args)
              {
                      String str = new String("jf");
                      str += new A();
                      System.out.print(str);
              }
                  public String toString()
                     {
                          return " a.i ="+i+"\n";
                     }
          }

          三、字符串轉換的優化

          按照上述說法,str = 1+2+str+3+4;語句似乎應該就應該生成5個String對象:

          1+2 =3,then 3→Integer(3)→"3" in pool? [假設如此] 
          "3"+str(in heap) = "3jf"     (in heap) 
          "3jf" +3 ,first 3→Integer(3)→"3" in pool? [則不創建] then "3jf3" 
          "3jf3"+4 create "4"  in pool 
          then "3jf34"

              這里我并不清楚3、4轉換成字符串后是否在池中,所以上述結果仍然是猜測。

              為了減少創建中間過渡性的字符串對象,提高反復進行串接運算時的性能,a Java compiler可以使用StringBuffer或者類似的技術,或者把轉換與串接合并成一步。例如:對于 a + b + c ,Java編譯器就可以將它視為[as if]

              new StringBuffer().append(a).append(b).append(c).toString();

              注意,對于基本類型和引用類型,在append(a)過程中仍然要先將參數轉換,從這個觀點看,str = 1+2+str+3+4;創建的字符串可能是"3"、"4"和"3jf34"[以及一個StringBuffer對象]。

              現在我仍然不知道怎么回答str = 1+2+str+3+4;創建了多少String的對象,。或許,這個問題不需要過于研究,至少SCJP不會考它。

          3、這又不同:str = "3"+"jf"+"3"+"4";
              如果是一個完全由字符串文字組成的表達式,則在編譯時,已經被優化而不會在運行時創建中間字符串。測試代碼如下:

          String str1 ="3jf34";
          String str2 ="3"+"jf"+"3"+"4"; 
            if(str1 == str2) {
                        System.out.println("str1 == str2");
                          }
            else {
                        System.out.println("think again");
                 } 
          if(str2.equals(str1)) 
          System.out.println("yet str2.equals(str1)");

              可見,str1與str2指向同一個對象,這個對象在pool中。所有遵循Java Language Spec的編譯器都必須在編譯時對constant expressions 進行簡化。JLS規定:Strings computed by constant expressions (ý15.28) are computed at compile time and then treated as if they were literals. 

              對于String str2 ="3"+"jf"+"3"+"4";我們說僅僅創建一個對象。注意,“創建多少對象”的討論是說運行時創建多少對象。

              BTW:編譯時優化

              String x = "aaa " + "bbb "; 
                 if (false) {        x = x + "ccc ";    }
                     x +=  "ddd ";    等價于:    String x = "aaa bbb ";    x = x + "ddd ";

          4、不變類
              String對象是不可改變的(immutable)。有人對str = 1+2+str+3+4;語句提出疑問,怎么str的內容可以改變?其實仍然是因為不清楚:引用變量與對象的區別。str僅僅是引用變量,它的值??它持有的引用可以改變。你不停地創建新對象,我就不斷地改變指向。[參考TIJ的Read-only classes。]

              不變類的關鍵是,對于對象的所有操作都不可能改變原來的對象[只要需要,就返回一個改變了的新對象]。這就保證了對象不可改變。為什么要將一個類設計成不變類?有一個OOD設計的原則:Law of Demeter。其廣義解讀是:

              使用不變類。只要有可能,類應當設計為不變類
          本文引自CSDN

          posted on 2007-11-07 10:25 java_蟈蟈 閱讀(868) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 桃源县| 克什克腾旗| 福鼎市| 榕江县| 榆树市| 丰镇市| 彰化县| 古浪县| 五莲县| 静安区| 鄂尔多斯市| 青州市| 大荔县| 青冈县| 迭部县| 桦南县| 前郭尔| 宣恩县| 航空| 丽江市| 化德县| 吴江市| 梓潼县| 西吉县| 天津市| 临泉县| 云浮市| 和硕县| 保德县| 胶州市| 北流市| 遂溪县| 利川市| 淮南市| 青浦区| 敦煌市| 天等县| 溧水县| 泽普县| 聊城市| 青浦区|