一、Equivalence Relation
现实中的每个对象实体都是独特的,所以无法完全相等,但有“相似性”,在人类语言和数学中,“绝对相等”是存在的。
等价关系:自反、对称、传递
二、
Three ways to regard equality
ADT是对数据的抽象, 体现为一组对数据的操作。
抽象函数AF:内部表示抽象表示
基于抽象函数AF定义ADT的等价操作
如果AF映射到同样的结果,则等价。
站在外部观察者角度:对两个对象调用任何相同的操作,都会得到相同的结果,则认为这
两个对象是等价的。反之亦然!
前提:当观察定义的等价和AF定义的等价相同时。
三、
==
vs.
equals()
==:引用等价性
equals():对象等价性
在自定义ADT时,需要根据对“等价”的要求,决定是否重写Object的equals()。
If you want to override a method:
– Make sure signatures match
– Use @Override so compiler has your back
– Do copy-and-paste declarations (or let IDE do it for you)
四、Implementing equals()
在Object中实现的缺省equals()是在判断引用等价性,这通常不是程序员所期望的,因此需要重写。
五、The Object contract
The contract of equals() in Object:
When you override the equals() method, you must adhere to its general contract:
The equals contract in English:
Reflexive – every object is equal to itself 自反性
Symmetric – if a.equals(b) then b.equals(a) 对称性
Transitive
– if
a.equals(b
) and
b.equals(c
), then
a.equals(c) 传递性
Consistent– equal objects stay equal unless mutated 一致性(用来判断等价的信息不发生变化时,多次比较的结果不变)
“Non-null”
–
a.equals(null
) returns false
Taken together these ensure that equals is a global
equivalence
relation
over all objects
对类的所有对象都生效
用“是否为等价关系”检验你的equals()是否正确
The
hashCode contract:程序中多次调用同一对象的
hashCode方法,都要返回相同值。不要求程序的多次执行时相同。等价的对象必须有相同的
hashCode。不相等的对象,也可以映射为同样的hashCode,但性能会变差。
Overriding hashCode():最简单方法:让所有对象的hashCode为同一常量,符合contract,但降低了hasTable效率。通过equals计算中用到的所有信息的hashCode组合出新的hashCode。两个equal的objects,一定要有同样的hashCode。
Always override hashCode() when you override equals() 除非你能保证你的ADT不会被放入到Hash类型的集合类中。
六、
Equality of Mutable Types
观察等价性:在不改变状态的情况下,两个mutable对象是否看起来一致。
行为等价性:调用对象的任何方法都展示出一致的结果。
当equals和hashcode的结果可能被可变影响时,hash table的RI会遭到破坏。
如果某个mutable的对象包含在Set集合类中,当其发生改变后,集合类的行为不确定,务必小心。
在JDK中,不同的mutable使用不同的等价性标准。
七、Autoboxing and Equality