论坛首页 Java企业应用论坛

Java通用方法

浏览 2297 次
该帖已经被评为隐藏帖
作者 正文
   发表时间:2010-02-25   最后修改:2010-02-25
Object中的所有非final方法(equals 、hashCode、toString、clone 和 finalize )       目的是为了Override而设计的

Equals不需要重写的几种情况:
1     一个类的每个实例本质上都是惟一的。对于代表了活动实体而不是值(value)的类比如Thread。

2     不关心一个类是否提供了"逻辑相等(logical equality)"测试功能。例如java.util.Random改写equals方法,他检查两个Random实例是否产生相同的随机数序列,但是设计者并不认为客户会需要这样的功能,在这样的情况下,从Object继承的equals实现已经足够了。

3      超类 已经改写了equals方法,从超类继承过来的子类也是合适的。例如大多数的Set从AbstractSet继承了equals实现,List实现从AbstractList继承了equals实现,Map实现从AbstractMap继承了equals实现

4      一个类是私有的,或者是包级私有的 ,并且可以确定他的equals方法永远不会被调用。
   
 public boolean  equals(Object o)  {
                throw new  UnsupportedOperationException();
    }

什么时候改写Object.equals?
当 一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念),而且超类也没有改写equals以实现期望的行为。
改写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,并且Y.equals(Z)也返回true时,那么X.equals(Z)也一定要返回true
4.    一致性  对于任意的引用值X和Y,如果用于equals比较的对象信息没有被修改的话,那么,多次调用X.equals(Y)要么一致的返回true要么一致的返回false。
5.     对于任意的非空引用值X,X.equals(null)一定返回false

对称性:
例如:
              
Public   final class  CaseInsensitveString  {
                       private  final   String  s ;
                     public  CaseInsensitveString  (String  s){
                          if(s==null) throw new NullPointerException();
                          this.s=s;
                     }
                @override  public boolean equals(Object o) {
                       if(o instance of CaseInsensitveString )
                              return  s.equalsIgnore(((CaseInsensitveString)o).s);
                         if(o instanceof String)
                               return s.equalsIgnoreCase((String)o);
                             retrun false;
                }
             …
           }

假设一个不区分大小写的字符串和一个普通的字符串
CaseInsensitveString   cis =new CaseInsensitveString  ("Polish");
String p ="polish";
这时 cis.equals(p)返回true 但是在String类中equals却不知道区分大小写的字符串所以s.equals(p)却返回了false,违反了对称性。
所以可以重构上述方法为
           
  @override  public boolean equals(Object o) {
                     return o instanceof CaseInsensitveString  &&((CaseInsensitveString  )o).s.equalsIgnoreCase(s); 
             }


传递性:如果一个对象等于第二个对象,第二个对象等于第三个对象,那么第一个对象一定等于第三个对象。
在父类和子类的情况下,子类将一个新的值组件添加到父类中,子类添加的信息就会影响到equals的比较结果。
                   
    public  class Point() {
                            private    final    int x;
                            private    final    int y;
                            public Point(int x,int y) {
                                  this.x=x;
                                  this.y=y;
                            }
                       @override public boolean equals(Object o) {
                              if(!(o instanceof Point ))
                                       return false ;
                              Point p =(Point)o;
                         retrun p.x==x&&p.y==y;
                     }
                     …
                 }   
                public class ColorPoint extends Point {
                     private  final Color color ;
                 public ColorPonit(int x,int y,Color color) {
                    super(x,y);
                    this color =color;
               }
           ….
        }

在这段代码中equals比较的是Point而把点的颜色给忽略了。。。改为:
 
 @override public boolean equals(Object o) {
                              if(!(o instanceof ColorPoint ))
                                       return false ;
                            retrun super.equals(o)&&((ColorPoint)o).color==color;
                     }

这种情况下在比较有色点和普通点,在相反的情况下则返回false如:
Point   p= new Point(1,2);
ColorPoint cp =new ColorPoint(1,2,Color.red);
p.equals(cp)
返回true  cp.equals(p)返回false 违反了对称性

 
 @override public boolean equals(Object o) {
                              if(!(o instanceof  Point ))
                                       return false ;
                             if(!(o instanceof ColorPoint))
                                     return o.equals(this);
                            retrun super.equals(o)&&((ColorPoint)o).color==color;
                     }

Point   p1= new Point(1,2);
ColorPoint p2 =new ColorPoint(1,2,Color.red);
ColorPoint p3 =new ColorPoint(1,2,Color.blue);
P1.equals(p2); true
P1.equals(p3);true;
P2.equals(p3);false;

违反了传递性。
解决办法:在一个抽象的(abstract)类的子类中增加新的值组件
一个抽象的Shape类,他没有任何值组件,Circle子类增加了一个radius域,Rectangle子类增加了length和width域,只要不直接创建父类的实例,就可以使用equals进行子类中实例的比较。

一致性:如果两个对象相等,他们就必须始终保持相等,除非他们中有一个或者俩个都被修改了。当你在写一个类的时候考虑这个类是否是不可变的,如果他是不可变的,就必须保证equals方法满足相等的对象要永远相等,不相等的永远不相等。
非空性:所有的对象都必须不等于null,equals方法必须使用instanceof操作符,检查其参数是否为的正确的类型:
                 
  @override public boolean equals (Object o) {
                             if(!(o instanceof MyType))
                                           return false; 
                              MyType mt =(MyType) o ;
                           …
                        }

总结实现equals方法:
1.使用“==”操作符检查“参数是否为这个对象的引用”。如果是,则返回true
2.使用instanceof操作符检查“参数是否为正确的类型”。如果不是则返回false
3.把参数转成正确的类型。
4.对于该类中的每个“关键域”,检查参数中是否与该对象中对应的域相匹配。
注意:不要将equals声明中的Object对象替换为其他的类型
Public boolean equals(MyClass  o) {
...
} 这个方法并没有重写Object.equals.因为他的参数应该是Object类型的,相反他重载了Object.equals。































论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics