浏览 2297 次
锁定老帖子 主题:Java通用方法
该帖已经被评为隐藏帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-02-25
最后修改:2010-02-25
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。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |