斗膽給Thinking in JAVA挑錯

          Posted on 2005-10-08 12:05 BlueO2 閱讀(515) 評論(0)  編輯  收藏 所屬分類: JAVA foundation
          今天晚上被討厭的vba郁悶,以后誰再跟我說vb簡單易用我跟誰急。由于計劃上每天都要繼續討論java基礎語言特性,所以最近也返璞歸真,重讀thinking in java。發現了一個問題如下:
          在第9章 持有你的對象arrays的比較章節,有如此代碼片斷:
          String[] s1 = new String[5];
          Arrays.fill(s1,"hi");
          String[] s2 = {"hi","hi","hi","hi","hi"};
          System.out.println(Arrays.equals(s1,s2));
          輸出結果true
          Bruce給出的解釋是s1的所有元素指向同一個對象,s2卻擁有5個不同對象,但是Arrays.equals比較的是內容,還特意強調通過Object.equals(),所以結果為true.
          首先,我們看看Arryas.fill(s1,"hi")如何工作:
          SRC:
          public static void fill(Object[] a, Object val) {
                  fill(a, 0, a.length, val);
              }
          public static void fill(Object[] a, int fromIndex, int toIndex,Object val){
                  rangeCheck(a.length, fromIndex, toIndex);
                  for (int i=fromIndex; i<toIndex; i++)
                      a[i] = val;
              }
          顯然所有的s1中原素指向了相同的一個對象"hi"這里Bruce沒錯,那么后面的s2是否擁有5個不同的對象呢?我們做以下代碼測試(其中捎帶著String類型的測試)
          import java.util.Arrays;
          public class profit{
                  public static void main(String args[]){
                          String s1 = "Hi";
                          String s2 = "Hi";
                          String s3 = new String("Hi");
                          String s4 = new String("Hi");
                          if(s1==s2) System.out.println("s1 s2 equal");
                          if(s3==s4) System.out.println("s3 s4 equal");
                          //System.out.println(s3.hashCode());
                          //System.out.println(s4.hashCode());
                          String[] strArray = new String[2];
                          Arrays.fill(strArray,"hello");
                          if(strArray[0]==strArray[1]) System.out.println("strArray equal");
                          String[] strArray2 = {"hello","hello"};
                          if(strArray2[0]==strArray2[1]) System.out.println("strArray2 equal");
                          String[] strArray3 = {new String("hello"),new String("hello")};
                          if(strArray3[0]==strArray[1]) System.out.println("strArray3 equal");

          輸出結果:
          ---------- Run ----------
          s1 s2 equal
          strArray equal
          strArray2 equal

          Output completed (1 sec consumed) - Normal Termination
          首先,各位應該明白最基礎的東西 ==實現的比較是淺比較,就是非reference指向的具體對象內容,而是是否指向了同一個對象。第二,String類型被設計為非可變類,就是說 String s1 = "hi";與String s2 = "hi";其實指向了同一個對象,只有用new構造函數的時候才會產生新的對象,而不管內容是否已經在內存中存在。如下文字闡述了一些:
          s = new String("Initial Value");
          每次都會調用構造器,生成新對象,性能低下且內存開銷大,并且沒有意義,因為String對象不可改變,所以對于內容相同的字符串,只要一個String對象來表示就可以了。也就說,多次調用上面的構造器創建多個對象,他們的String類型屬性s都指向同一個對象。
          上面的結論還基于這樣一個事實:對于字符串常量,如果內容相同,Java認為它們代表同一個String對象。而用關鍵字new調用構造器,總是會創建一個新的對象,無論內容是否相同
          ok,回到我們的話題上來String[] s2 = {"hi","hi","hi","hi","hi"};是否產生了5個不同的對象呢?我寫的簡單的測試代碼

          String[] strArray2 = {"hello","hello"};
           if(strArray2[0]==strArray2[1]) System.out.println("strArray2 equal");
          的結果大家應該得出了結論了吧。
          那么,bruce給出的代碼的結果之所以為true就是因為,這么多個數組中的成員"hi"其實都是同一個對象。那么我們繼續看Arrays.equals是否比較的內容呢?
          SRC:
          public static boolean equals(Object[] a, Object[] a2) {
                  if (a==a2)
                      return true;   //如果指向同一對象,當然是相同的,返回true
                  if (a==null || a2==null)
                      return false;  //如果為null就沒有相等的一說,false

                  int length = a.length;
                  if (a2.length != length)  //長度不同
                      return false;

                  for (int i=0; i<length; i++) {
                      Object o1 = a[i];
                      Object o2 = a2[i];
                      if (!(o1==null ? o2==null : o1.equals(o2)))  //此處為關鍵,object的equals比較,Arrays.equals并沒有專門為String類型重載此方法,全部都依賴Object的方法比較
                          return false;
                  }

                  return true;
              }

          那么我們再看看Object這個樹根的equals方法吧:
          public boolean equals(Object obj) {
           return (this == obj);
              }

          短短幾行代碼,但是,是淺比較毫無疑問,所以,bruce說的,依賴的是Object.equals,比較的是內容,更是錯誤的。
          但是必須強調的是,當String數組傳遞進來的時候,由于java的RTTI執行期型別辨識,Arryas.equals調用的其實是String.equals方法,而String.equals方法是比較內容的,所以,此處我想是bruce沒有說明白,而又偏偏列舉了String的例子。如果是自己寫的類有沒有復寫equals方法,此時就調用Object.equals了,那么根本不可能比較內容,所以Arrays.equals大家一定要知道怎么回事再用。

          posts - 29, comments - 3, trackbacks - 0, articles - 0

          Copyright © BlueO2

          主站蜘蛛池模板: 朝阳县| 平定县| 太原市| 博兴县| 昌江| 望城县| 三门峡市| 包头市| 亚东县| 德安县| 仁怀市| 汪清县| 新营市| 福安市| 右玉县| 浪卡子县| 朝阳县| 法库县| 栖霞市| 德格县| 晴隆县| 子长县| 万盛区| 衡阳市| 新丰县| 马公市| 昆明市| 获嘉县| 明光市| 云和县| 武宁县| 台南县| 榆中县| 昆山市| 高阳县| 孟村| 巴彦县| 手游| 宕昌县| 双流县| 思南县|