例:(通过以observation来确定等价性)判断下流对象是否等价
(因为此函数的方法只是判断分钟转化为秒并加上秒的数值是否相等即可判断两个对象是否相等。所以d1、d3、d4都是“相等的”)
“==”:表示引用等价性(比较在内存中的地址)
“equals()”:表示对象等价性(比较对象的内容)(在自定义ADT时,需要重写Object的equals())
例:判断下列表示的“相等”
(注意:这里的equals()方法不是重写Object的方法,而是overload。因为在重载的equals的方法中只是返回长度,并且d2是Duration类型的,与Duration类中的equals方法的参数类型相匹配,所以第一个返回true。然而o2是Object类型的不与Duration类中的equals方法的参数类型相匹配,所以调用的是Object中的equals()方法,比较引用,所以返回false)
也可以重写 equals()方法:↓↓↓
(用instanceof函数判断是不是某个类的实例)(注意instanceof是动态检查,不是静态检查)
hashcode的合约:如果两个对象根据Object的方法equals来判断是相等的,那么根据两个对象的hashcode的方法必须产生相同的Interger的返回值结果。(两个equal的objects,一定要有同样的hashcode.)
一般的规则:当你重写了equals()时,总是一定要重写hashcode()。
例:下面这段代码需要怎么重写hashcode()函数
解:因为equals()函数,仅有当两个Person的lastName相等时,才返回true;所以需要当返回true时,两个对象的hashcode()函数返回结果相同。所以,只有第一个和第三个满足要求(但第一个全部映射到一个数,虽然满足要求,但效率太低)
对于可变数据类型来说的“相等”:
(但有些时候,观察等价性可能导致bug,甚至可能破坏RI)
**例:假设我们创建了一个List,并把它放进一个Set
我们能检测出这个set是包含这个List的:
现在我们修改List,我们发现这个List就不在Set中了:
更糟糕的是:当我们用迭代器迭代时发现List任然在Set中,但用函数contains却说它不在了。
*解析:因为List是可变的对象,在标准的java实现类collection类中的List,可变性影响着equals()和hashcode()的结果;当你将List放入Hashset后,它就被存放在哈希桶/散列桶中,并对应着hashcode()的结果;当List被改变后,它的hashcode()也被改变了,但是Hashset并没有意识到它应该移动到一个不同的桶中,所以它再也找不到了;当equals()和hashcode()函数会被mutation(变值器)影响时,我们可以打破哈希表的RI适用对象作为一个key。
例:看下列按不同要求的等价性是否满足(注意所给数据类型为mutable)
(false;true;false;false;false;true)(行为等价性就要比较地址是否相同)
(false;true;true;false;true;true)(观察等价性:仅仅看内容是否一样)
**例:看原始数据类型和包装后的数据类型的区别
解:(一定要注意原始数据类型和包装数据类型(对象数据类型)的区别:基本数据类型的数据 只有值 没有ID,即相同的值的变量都指向同一块内存空间;而对象数据类型有值也有ID)
**例:what do we get out of the map?
false;