<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    讀《effective java》學習筆記三

    第六條 在改寫equals的時候請遵守通用規定
      有一種“值類”可以不要求改寫equals方法,類型安全枚舉類型,因為類型安全枚舉類型保證每一個值之多只存在一個對象,所有對于這樣的類而言,Object的queals方法等同于邏輯意義上的equals方法。
     
      在改寫equals方法的時候,要遵循的規范: 
            1,自反性。對任意的引用值x,x.equals(x)一定是true
            2,對稱性。對于任意的引用值x和y,當且僅當y.equals(x)返回true時,x.equals(y)也一定返回true.
            3,傳遞性。對于任意的引用值x,y和z,如果x.equals(y)==true and y.equals(z)==true,so x.equals(z)==true.
            4,一致性。對于任意的引用值x和y,如果用于equals比較的對象信息沒有被修改的話,那么,多次調用x.equals(y)要么一致地返回true,要么一致地返回false.
            5,非空性。對于任意的非空引用值x,x.equals(null)一定返回false.
            
      自反性:要求一個對象必須等于其自身。一個例子:你把該類的實例加入到一個集合中,則該集合的contains方法
    將果斷地告訴你,該集合不包含你剛剛加入的實例. 

      對稱性:
      例如:
         public final class CaseInsensitiveString{
               private String s;
               public CaseInsensitiveString(String s){
                  if(s==null)   throw new NullPointerException();
                  this.s=s;
               }
               public boolean equals(Object o){
                  if(o instanceof CaseInsensitiveString)
                     return s.equalsIgnoreCase(((CaseInsensitiveString)o).s);
                  if(o instanceof String)
                     return s.equalsIgnoreCase((String)o);
                   return false;
                }
              }
    調用:
       CaseInsensitiveString cis=new CaseInsensitiveString("Polish");
           String s="polish";
    正如我們期望的:cis.equals(s)==true but s.equals(cis)==false
    這就違反了對稱性的原則.為了解決這個問題,只需把企圖與String互操作的這段代碼從equals方法中去掉舊可以了.這樣做之后,你可以重構代碼,使他變成一條返回語句:
    public boolean equals(Object o){
       return o instanceof CaseInsensitiveString && ((CaseInsensitiveString)o).s.equalsIgnoreCase(s);
    }

     

    傳遞性---即如果一個對象等于第二個對象,并且第二個對象又等于第三個對象,則第一個對象一定等于第三個對象。
    例如:
           public class Point{
               private final int x;
               private final int y;
               public Point(int x,int y){
                    this.x=x;
                    this.y=y;
              }
              public boolean equals(Object o){
                 if(!(o instanceof Point))
                  return false;
                 Point p=(Point)o;
                 return p.x==x&&p.y==y;
              }
         }
    現在我們來擴展這個類,為一個點增加顏色信息:
       public class ColorPoint extends Point{
          private Color color;
          public ColorPoint(int x,int y,Color color){
              super(x,y);
              this.color=color;
          }
       }
    分析: equals方法會怎么樣呢?如果你完全不提供equals方法,而是直接從Point繼承過來,那么在equals座比較的時候顏色信息會被忽略掉。如果你編寫一個equals方法,只有當實參是另一個有色點,并且具有同樣的位置和顏色的時候,它才返回true:
           public boolean equals(Object o){
              if(!(o instanceof ColorPoint)) return false;
              ColorPoint cp=(ColorPoint)o;
              return super.equals(o) && cp.color==color;
           }
    分析:這個方法的問題在于,我們在比較一個普通點和一個有色點,以及反過來的情形的時候,可能會得到不同的結果。前一種比較忽略了顏色信息,而后一種比較總是返回false,因為實參的類型不正確。例如:
         Point p=new Point(1,2);
         ColorPoint cp=new ColorPoint(1,2,Color.RED);
    然后:p.equals(cp)==true but cp.equals(p)==false

    修正:讓ColorPoint.equals在進行“混合比較”的時候忽略顏色信息:
       public boolean equals(Object o){
           if(!(o instanceof Point)) return false;
           if(!(o instanceof ColorPoint)) return o.equals(this);
           ColorPoint cp=(ColorPoint)o;
           return super.equals(o) && cp.color==color;
       }
    這種方法確實提供了對稱性,但是卻犧牲了傳遞性:
       ColorPoint p1=new ColorPoint(1,2,Color.RED);
       Point p2=new Point(1,2);
       ColorPoint p3=new ColorPoint(1,2,Color.BLUE);
    此時:p1.equals(p2)==true and p2.equals(p3)==true but p1.equals(p3)==false很顯然違反了傳遞性。前兩個比較不考慮顏色信息,而第三個比較考慮了顏色信息。

    結論:要想在擴展一個可實例華的類的同時,既要增加新的特征,同時還要保留equals約定,沒有一個簡單的辦法可以做到這一點。根據"復合優于繼承",這個問題還是有好的解決辦法:我們不讓ColorPoint擴展Point,而是在ColorPoint中加入一個私有的Point域,以及一個公有的視圖方法,此方法返回一個與該有色 點在同一位置上的普通Point對象:
        public class ColorPoint{
           private Point point;
           private Color color;
           public ColorPoint(int x,int y,Color color){
             point=new Point(x,y);
             this.color=color;
           }
           public Point asPoint(){
               return point;
           }
         
           public boolean equals(Object o){
               if(!(o instanceof ColorPoint)) return false;
               ColorPoint cp=(ColorPoint)o;
               return cp.point.equals.(point) && cp.color.equals(color);
           }
        }
       
    注意,你可以在一個抽象類的子類中增加新的特征,而不會違反equals約定。

     

    一致性:
     如果兩個對象相等的話,那么它們必須始終保持相等,除非有一個對象被修改了。由于可變對象在不同的時候可以與不同的對象相等,而非可變對象不會這樣,這個約定沒有嚴格界定。
     


    非空性:沒什么好說的。

    1,使用==操作符檢查“實參是否為指向對象的一個應用”。如果是的話,則返回true。
           2,使用instanceof操作符檢查“實參是否為正確的類型”。如果不是的話,則返回false。
           3,把實參轉換到正確的類型。
           4,對于該類中每一個“關鍵(significant)”域,檢查實參中的域與當前對象中對應的域值是否匹配
         if (!(this.field == null ? o.field == null : this.equals(o.field)))
         //或者寫成 if(!(this.field == o.field || (this.field != null && this.field.equals(o.field)))) 對于this.field和o.field通常是相同的對象引用,會更快一些。
           return false;
         //比較下一個field
         //都比較完了
         return true;
         
    5.最后還要確認以下事情
       5.1)改寫equals的同時,總是(必須)要改寫hashCode方法(見【第8條】),這是極容易被忽略的,有極為重要的
       5.2)不要企圖讓equals方法過于聰明
       5.3)不要使用不可靠的資源。如依賴網絡連接
       5.4)不要將equals聲明中的Object對象替換為其他類型。
             public boolean equals(MyClass) 這樣的聲明并不鮮見,往外使程序員數小時搞不清楚為什么不能正常工作
             原因是這里是重載(overload)而并不是改寫(override)(或稱為覆蓋、重寫)
             相當于給equals又增加了一個實參類型為MyClass的重載,而實參為Object的那個equals并沒有被改寫,依然還是從Object繼承來的最初的那個equals,所總是看不到程序員想要的效果。因為類庫或其他人寫的代碼都是調用實參為Object型的那個equals方法的(別人又如何在事前知曉你今天寫的MyClass呢?)

    posted on 2009-07-28 20:30 胡鵬 閱讀(220) 評論(0)  編輯  收藏 所屬分類: 讀《effective java》筆記

    導航

    <2009年7月>
    2829301234
    567891011
    12131415161718
    19202122232425
    2627282930311
    2345678

    統計

    常用鏈接

    留言簿(3)

    隨筆分類

    隨筆檔案

    agile

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 四虎影视在线永久免费看黄| 中文亚洲AV片在线观看不卡 | 四虎精品亚洲一区二区三区| 一级毛片试看60分钟免费播放| 久久精品国产亚洲夜色AV网站| 100000免费啪啪18免进| 无套内谢孕妇毛片免费看看| 久久夜色精品国产亚洲AV动态图| 最近免费中文字幕4| 中国在线观看免费的www| 亚洲AV无码一区二区三区人| 亚洲欧洲日产国码一级毛片| 男女做羞羞的事视频免费观看无遮挡| 国产天堂亚洲精品| 911精品国产亚洲日本美国韩国 | 国产色无码精品视频免费| 久久亚洲精品国产精品婷婷 | 亚洲成AV人片天堂网无码| 思思99re66在线精品免费观看| 人妻在线日韩免费视频| 亚洲精品无码av片| 精品亚洲成a人片在线观看| 亚洲?v女人的天堂在线观看| 国产一卡二卡3卡四卡免费| 男人天堂免费视频| 亚洲AV日韩AV无码污污网站| 亚洲欧洲精品久久| 在线观看亚洲av每日更新| 免费无码看av的网站| 中文字幕免费在线观看| 美女巨胸喷奶水视频www免费| 亚洲av无码一区二区三区四区| 亚洲日韩在线视频| 亚洲精品乱码久久久久久久久久久久| 色吊丝永久在线观看最新免费 | 亚洲一区AV无码少妇电影☆| 国产免费爽爽视频免费可以看| 一二三四免费观看在线电影 | 亚洲欧洲成人精品香蕉网| 免费a级毛片网站| 噜噜嘿在线视频免费观看|