我们爱分享---Obey the general contract when overriding equals

shine333 2011-09-14 06:25:12
加精
这两天热度有点低,也没什么好写的,就随便奉献上Effective Java中的一条规则
Obey the general contract when overriding equals

今天只讲其中的一个原则及其注意事项:
symmetric: For any reference values x and y, x.equals(y) must return true if and only if y.equals(x) returns true.
可以称之为对称性或者交换性原则,即x.equals(y)返回true是y.equals(x)的充要条件。

理论大家会讲,但是在override的时候,大家很容易出错。


public class A {
public int x;
public boolean equals(Object obj) {
if (! (obj instanceof A)) {
return false;
}
A that = (A) obj;
return this.x == that.x;
}
}


这段代码粗看上去没有任何问题(null instanceof A也是false),但实际上,这段代码在将来的某个时刻很有可能导致symmetric原则被破坏。

public class B extends A {
public int y;
public boolean equals(Object obj) {
if (! (obj instanceof B)) {
return false;
}
B that = (B) obj;
return super.equals(obj) && this.y == that.y;
}
}

此时,无论B中间的equals方法如何调整,都会导致symmetric原则被破坏:

A a = new A();
B b = new B();

System.out.println(a.equals(b)); // true,B是A的子类,b当然是instanceof A,而且由于之比较a.x和b.x,所以true
System.out.println(b.equals(a)); // false,a不是B的实例


老实说,这个世界上没有一个完美的修正方案,这点不光是Java,C#等OO语言都有这个问题。

1 如果所有的类都可以修改的话,那么你可以在每一个类中都override equals方法,并用this.getClass() == obj.getClass()来判断(只适用于所有类都是自己写的,最顶层的父类直接继承自Object,而且,每一层都添加了字段)
2 如果能够用组合的话,尽量使用组合,而不是继承“Favor composition over inheritance”,通过这种方式绕过去
3 忍受它,因为这个问题,其实你天天可能在JDK中间碰到这个问题,比如java.util.Date及其java.sql包中间的子类,所以当你如果可能碰到java.util.Date实例和java.sql.Timestamp实例做equals的时候,你就该当心了。
...全文
2109 87 打赏 收藏 转发到动态 举报
写回复
用AI写文章
87 条回复
切换为时间正序
请发表友善的回复…
发表回复
a821808 2012-06-13
  • 打赏
  • 举报
回复
来学习的,多谢分享。
冰雪燕恒 2011-12-15
  • 打赏
  • 举报
回复
[Quote=引用 55 楼 magong 的回复:]
引用 54 楼 bearkin 的回复:

所以我说hashCode的比较结果和equals的比较结果必须一样 那个帖子说可以不一样 我就很诧异

忍不住想说两句:

hash一样的,可以不equals
equals的,hash必然一样

通常可以把hashCode看做是一种初排。初排一致的,equals必须能细分是否真的equal。初排就不一致的,equals居然返回true的……
[/Quote]
原来还以为对hashCode和equals清楚地,看完一下子糊涂了,
前辈这里的初排是不是有点过滤的意思,先用哈hashCode比较,不同的hashCode的equals一定false,只有hashCode相同才有资格去equals,而equals的hashCode一定一致
???
impossible_no 2011-10-12
  • 打赏
  • 举报
回复
呵呵 这个帖子不错啊 收藏了
dokia123 2011-10-10
  • 打赏
  • 举报
回复
<b><i> </i></b>
zl3450341 2011-10-10
  • 打赏
  • 举报
回复
这个贴我居然漏了。坦克大哥不好意思哈。收藏一下。整理起来了
luyun2011 2011-09-20
  • 打赏
  • 举报
回复
学习了!太容易搞混了!!
tutu_zhoujun 2011-09-19
  • 打赏
  • 举报
回复
来学习的,多谢分享。
shine333 2011-09-19
  • 打赏
  • 举报
回复
[Quote=引用 77 楼 x19881216 的回复:]

原來坦克哥的帖子多回复是有分的
[/Quote]
小绵羊 2011-09-19
  • 打赏
  • 举报
回复
原來坦克哥的帖子多回复是有分的
鲤鱼 2011-09-18
  • 打赏
  • 举报
回复
学习下
pr262760668 2011-09-18
  • 打赏
  • 举报
回复
学习!!容易搞错!!谢谢楼主!
duqiling 2011-09-18
  • 打赏
  • 举报
回复
学习!!容易搞错!!谢谢楼主!
wjlazio 2011-09-17
  • 打赏
  • 举报
回复
看看,学习了。。。。
shine333 2011-09-16
  • 打赏
  • 举报
回复
[Quote=引用 56 楼 gsy999 的回复:]
...
//如果类不匹配,它们是不会相等的
if(getClass() != otherObject.getClass())
return false;
...
[/Quote]
这个结论“如果类不匹配,它们是不会相等的”其实不是100%正确的。因为根据Object.equals规定的契约中,并没有规定两者类型必须一致
比如:

List<Integer> list1 = Arrays.asList(0,1,2,3);
List<Integer> list2 = new ArrayList<Integer>(list1);
List<Integer> list3 = new CopyOnWriteArrayList<Integer>(list1);
System.out.println(list1.equals(list2));
System.out.println(list2.equals(list1));
System.out.println(list1.equals(list3));
System.out.println(list3.equals(list1));
System.out.println(list2.equals(list3));
System.out.println(list3.equals(list2));

list1, list2都是AbstractList的子类,equals定义在AbstractList中,
list3是直接继承自Object,自己实现了List接口,自己override了equals

当然,这个只是字面意思上的理解。你的代码比契约更严格,没什么大问题。

另外,在不考虑效率的场合,我直接在父类中,使用org.apache.commons.lang.builder.EqualsBuilder.reflectionEquals(Object, Object)方法
woniu4500 2011-09-16
  • 打赏
  • 举报
回复
求楼主赏分啊,我发帖木有分数啦,跪求啊
liuyuhua0066 2011-09-16
  • 打赏
  • 举报
回复
绝对没有找茬的意思。误会,误会了,九哥。
只是讨论帖子而已。
[Quote=引用 64 楼 bearkin 的回复:]
引用 62 楼 liuyuhua0066 的回复:
强调类型相同更应该是用getClass而不是instanceof。

引用 61 楼 bearkin 的回复:
引用 58 楼 liuyuhua0066 的回复:
我就不信用这个方式override equals方法还会出错。
为什么要用instanceof呢?

引用 56 楼 gsy999 的回复:
引用楼主 shine33……
[/Quote]
BearKin 2011-09-16
  • 打赏
  • 举报
回复
[Quote=引用 62 楼 liuyuhua0066 的回复:]
强调类型相同更应该是用getClass而不是instanceof。

引用 61 楼 bearkin 的回复:
引用 58 楼 liuyuhua0066 的回复:
我就不信用这个方式override equals方法还会出错。
为什么要用instanceof呢?

引用 56 楼 gsy999 的回复:
引用楼主 shine333 的回复:
这两天热度有点低,也没什么好写的,就随……
[/Quote]

两边互相X一下 没说就那么写一次
感觉你找俺茬 你想说用getClass().getName()比较就直接说呗 还让俺出丑..
cenlulu 2011-09-16
  • 打赏
  • 举报
回复
<STRONG> </STRONG>
liuyuhua0066 2011-09-16
  • 打赏
  • 举报
回复
强调类型相同更应该是用getClass而不是instanceof。
[Quote=引用 61 楼 bearkin 的回复:]
引用 58 楼 liuyuhua0066 的回复:
我就不信用这个方式override equals方法还会出错。
为什么要用instanceof呢?

引用 56 楼 gsy999 的回复:
引用楼主 shine333 的回复:
这两天热度有点低,也没什么好写的,就随便奉献上Effective Java中的一条规则
Obey the general contract when ov……
[/Quote]
BearKin 2011-09-16
  • 打赏
  • 举报
回复
[Quote=引用 58 楼 liuyuhua0066 的回复:]
我就不信用这个方式override equals方法还会出错。
为什么要用instanceof呢?

引用 56 楼 gsy999 的回复:
引用楼主 shine333 的回复:
这两天热度有点低,也没什么好写的,就随便奉献上Effective Java中的一条规则
Obey the general contract when overriding equals

今天只讲其中的一……
[/Quote]

强调类型相同
加载更多回复(57)
目录如下: 1 Introduction 2 Creating and Destroying Objects Item 1: Consider static factory methods instead of constructors Item 2: Consider a builder when faced with many constructor parameters Item 3: Enforce the singleton property with a private constructor or an enum type Item 4: Enforce noninstantiability with a private constructor Item 5: Prefer dependency injection to hardwiring resources Item 6: Avoid creating unnecessary objects Item 7: Eliminate obsolete object references Item 8: Avoid finalizers and cleaners Item 9: Prefer try-with-resources to try-finally 3 Methods Common to All Objects Item 10: Obey the general contract when overriding equals Item 11: Always override hashCode when you override equals Item 12: Always override toString Item 13: Override clone judiciously Item 14: Consider implementing Comparable 4 Classes and Interfaces Item 15: Minimize the accessibility of classes and members Item 16: In public classes, use accessor methods, not public fields Item 17: Minimize mutability Item 18: Favor composition over inheritance Item 19: Design and document for inheritance or else prohibit it Item 20: Prefer interfaces to abstract classes Item 21: Design interfaces for posterity Item 22: Use interfaces only to define types Item 23: Prefer class hierarchies to tagged classes Item 24: Favor static member classes over nonstatic Item 25: Limit source files to a single top-level class 5 Generics Item 26: Don’t use raw types Item 27: Eliminate unchecked warnings Item 28: Prefer lists to arrays Item 29: Favor generic types Item 30: Favor generic methods Item 31: Use bounded wildcards to increase API flexibility Item 32: Combine generics and varargs judiciously Item 33: Consider typesafe heterogeneous containers 6 Enums and Annotations Item 34: Use enums instead of int constants Item 35: Use instance fields instead of ordinals Item 36: Use EnumSet instead of bit fields Item 37: Use EnumMap instead of ordinal indexing Item 38: Emulate extensible enums with interfaces Item 39: Prefer annotations to naming patterns Item 40: Consistently use the Override annotation Item 41: Use marker interfaces to define types 7 Lambdas and Streams Item 42: Prefer lambdas to anonymous classes Item 43: Prefer method references to lambdas Item 44: Favor the use of standard functional interfaces Item 45: Use streams judiciously Item 46: Prefer side-effect-free functions in streams Item 47: Prefer Collection to Stream as a return type Item 48: Use caution when making streams parallel 8 Methods Item 49: Check parameters for validity Item 50: Make defensive copies when needed Item 51: Design method signatures carefully Item 52: Use overloading judiciously Item 53: Use varargs judiciously Item 54: Return empty collections or arrays, not nulls Item 55: Return optionals judiciously Item 56: Write doc comments for all exposed API elements 9 General Programming Item 57: Minimize the scope of local variables Item 58: Prefer for-each loops to traditional for loops Item 59: Know and use the libraries Item 60: Avoid float and double if exact answers are required Item 61: Prefer primitive types to boxed primitives Item 62: Avoid strings where other types are more appropriate Item 63: Beware the performance of string concatenation Item 64: Refer to objects by their interfaces Item 65: Prefer interfaces to reflection Item 66: Use native methods judiciously Item 67: Optimize judiciously Item 68: Adhere to generally accepted naming conventions 10 Exceptions Item 69: Use exceptions only for exceptional conditions Item 70: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors Item 71: Avoid unnecessary use of checked exceptions Item 72: Favor the use of standard exceptions Item 73: Throw exceptions appropriate to the abstraction Item 74: Document all exceptions thrown by each method Item 75: Include failure-capture information in detail messages Item 76: Strive for failure atomicity Item 77: Don’t ignore exceptions 11 Concurrency Item 78: Synchronize access to shared mutable data Item 79: Avoid excessive synchronization Item 80: Prefer executors, tasks, and streams to threads Item 81: Prefer concurrency utilities to wait and notify Item 82: Document thread safety Item 83: Use lazy initialization judiciously Item 84: Don’t depend on the thread scheduler 12 Serialization Item 85: Prefer alternatives to Java serialization Item 86: Implement Serializable with great caution Item 87: Consider using a custom serialized form Item 88: Write readObject methods defensively Item 89: For instance control, prefer enum types to readResolve Item 90: Consider serialization proxies instead of serialized instances

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧