Java笔记 ADT与OOP中的等价性
一、等价性equals()和"=="
1.等价关系
-
等价关系是指对于关系E ⊆ T x T,满足:
(1)自反性
x.equals(x)必须返回true
(2)对称性
x.equals(y)与y.equals(x)的返回值必须相等
(3)传递性
若x.equals(y)为true,且y.equals(z)也为true,那么x.equals(z)必须为true -
从使用者/外部的角度去观察
我们说两个对象相等,当且仅当使用者无法观察到它们之间有不同,即每一个观察总会都会得到相同的结果。
例如对于两个集合对象 {1,2} 和 {2,1},我们就无法观察到不同:
|{1,2}| = 2, |{2,1}| = 2
1 ∈ {1,2} is true, 1 ∈ {2,1} is true
3 ∈ {1,2} is false, 3 ∈ {2,1} is false
(使用者/外部的角度也就是从结果的角度出发去观察)
2.equals()方法与"=="
-
“==”------引用等价性
它测试的是指向相等(referential equality)。如果两个索引指向同一块存储区域,那它们就是指向相等的。
对于之前提到过的快照图来说,指向相等就意味着它们的箭头指向同一个对象。 -
equals()------引用等价性 or 对象等价性
在每一个ADT中,equals操作必须合理定义。
在自定义ADT时,可能需要重写Object的equals()方法,因为在Object中实现的缺省equals()是在判断引用等价性,如图所示:
同时,equals()也可经重写后测试对象值相等(object equality)。如果两个索引指向的存储区域中的两个抽象值是相等的,那它们就是对象值相等的。
当重写equals()方法时,应使用@Override注释。Java编译器将检查超类中是否确实存在具有相同签名的方法,如果在签名中犯了错误,则会给出一个编译器错误。
3.instanceof
-
instanceof运算符
(1)instanceof是Java中的二元运算符,左边是对象,右边是类;当对象是右边类或子类所创建对象时,返回true;否则,返回false。
(2)使用instanceof是动态检查,而非静态检查
(3)不要在父类型中使用instanceof检查子类型。 -
注意事项
(1)左边的对象实例不能是基础数据类型
(2)左边的对象实例和右边的类不在同一个继承树上
(3)null用instanceof跟任何类型比较时都是false
二、hashCode()方法
1.针对不可变类型
-
equals()应该比较抽象值是否相等。
-
hashCode()应该将抽象值映射为整数。
-
所以不可变类型应该同时覆盖equals()和hashCode()。
2.针对可变类型
-
equals()应该比较索引,就像"=="一样。
-
hashCode()应该将索引映射为整数。
-
所以可变类型不应该将equals()和hashCode()覆盖,而是直接继承Object中的方法。Java没有为大多数聚合类遵守这一规定,这也许会导致上面看到的隐秘bug。
3.equals()与hashcode()的比对
-
equals与hashCode两个方法均属于Object对象。equals()可以根据我们的需求进行重写,用来判断是否是同一个内容或同一个对象,具体是判断什么,怎么判断得看怎么重写,默认的equals()是比较地址。
-
hashCode方法返回一个int的哈希码, 同样可以重写来自定义获取哈希码的方法。
-
equals判定为相同,hashCode一定相同。equals判定为不同,hashCode不一定不同。
-
hashCode必须为两个被该equals()方法视为相等的对象产生相同的结果。
-
与equals()方法类似,hashCode()方法可以被重写。JDK中对hashCode()方法的作用,以及实现时的注意事项做了说明:
(1)hashCode()在哈希表中起作用,如java.util.HashMap。
(2)如果对象在equals()中使用的信息都没有改变,那么hashCode()值始终不变。
(3)如果两个对象使用equals()方法判断为相等,则hashCode()方法也应该相等。
(4)如果两个对象使用equals()方法判断为不相等,则不要求hashCode()也必须不相等;但是开发人员应该认识到,不相等的对象产生不相同的hashCode可以提高哈希表的性能。