目录
▪三种看待相等的方法
▪不变类型的相等
▪对象契约
▪可变类型的相等
▪equals()和hashCode()的最终规则
▪自动装箱和相等
对于抽象数据类型,抽象函数解释了如何将具体表示值解释为抽象类型的值,我们还了解了抽象函数的选择如何决定如何编写实现ADT的每个操作的代码;
AF决定了ADT中各操作的实现 ,可通过AF判定ADT中操作的等价
使用AF或关系
使用抽象函数。回想一下抽象函数AF: R→A将数据类型的具体实例映射到它们对应的抽象值。为了使用AF作为等式的定义,我们可以说当且仅当AF(a)=AF(b)时a = b。
使用观察
从观察的角度 ,对两个对象的任何同一操作都会得到相同的结果 ,对于ADT,“观察”意味着调用对象上的操作。因此,当且仅当不能通过调用抽象数据类型的任何操作来区分两个对象时,它们才相等
== vs. equals()
Java有两种不同的操作来测试相等性,它们具有不同的语义
The == operator compares references
它测试引用相等性。如果两个引用指向内存中的相同存储,则它们是==。对于快照图,如果箭头指向同一个对象气泡,则两个引用==。
equals()操作比较对象内容——换句话说,对象相等
必须为每个抽象数据类型适当地定义equals操作, 定义新数据类型 时,需要考虑等价的含义,然后实现equals()方法
对于基本数据类型,必须使用==;
对象引用类型
在java中,==只是测试引用标识,它不比较对象内容。
-完全由对象实现。等于,即使对象。等号已被重写
这很少是您想要的!-你应该(几乎)总是使用.equals
如果我们传递一个对象引用,就像在d1.equals(o2)中那样,我们最终调用equals(Object)实现
如果我们传递一个Duration引用,就像在d1.equals(d2)中一样,我们最终调用equals(Duration)版本
即使o2和d2在运行时 指向了统一对象,但结果不同,出现了等价的不一致问题
public final class PhoneNumber {
private final short areaCode; private final short prefix; private final short lineNumber;
@Override public boolean equals(Object o) { if (!(o instanceof PhoneNumber)) return false;
PhoneNumber pn = (PhoneNumber) o; return pn.lineNumber == lineNumber && pn.prefix == prefix && pn.areaCode == areaCode;
} ...
}
运算符instanceof操作符测试对象是否是特定类型的实例。使用instanceof是动态类型检查,而不是静态类型检查。通常,在面向对象编程中使用instanceof是一种不好的做法。除了实现equals之外,任何地方都应该禁止它。此禁止还包括检查对象运行时类型的其他方法。例如,getClass()也是不允许的。
重写Object类中equals()时,需要满足约定
满足等价性(自反,对称,传递)
一致性,在比较中用到的信息没有被修改的情况下,多 次比较结果应始终相同
使用equals方法判定相等的两个对象,其 hashCode必须产生相同的结果。
对于非空引用x, x.equals(null)应该返回false;
自反性, 对称性 ,传递性 ,一致性;
对于任何非空的参考值x和y,多次调用x.equals(y)始终返回true或false,条件是不修改对象上的equals比较中使用的信息
对于任何非空的参考值x, x.equals(x)必须返回true。
哈希表实现了键-值之间的映射
哈希表的查询时间为常 数(线性),性能优于trees或lists,且不需要排好序或其他特殊要求,除了需 要提供equals和hashCode方法
哈希表是如何工作的
它包含一个数组,该数组初始化为与我们期望插入的元素数量相对应的大小
键值对中的 key被映射为hashcode,对应到数组的index, hashcode决定了数据被存储 到数组的那个位置
哈希表的rep不变式包括键位于哈希码决定的槽中的基本约束
hashcode设计时会尽量确保均匀分布到数组
当多个key散列到同一个index时(冲突),哈希表维护一个列表 来记录这些键值对(bucket)
首先利用hashCode()产生的hashcode确定slot(index)
再用 equals()方法在bucket中找到匹配的key
只要比较操作用到的信息没有被修 改,那么对这同一个对象调用多次,hashCode()方法必须始终返回相同整数
如果equals比较相等,则要求hashcode相 等;如果equals不等,则hashcode是否相等均可,但最好不等(提升性能)
如果两个对象根据equals(Object)方法是不相等的,那么在每个对象上调用hashCode方法必须产生不同的整数结果,这是不需要的。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能
两个对象equals操作相等,则hashcode必须相等。因此,重写equals时,必 须重写hashCode。
构造hashcode时考 虑对象的所有字段,以避免不相等对象产生相同hashcode
除非对象可变,否 则hashcode不能修改
最简单方法:让所有对象的hashCode为同一 常量,符合contract,但降低了hashTable效率
通过 equals计算中用到的所有字段的hashCode组合出新的hashCode
为什么对象契约要求相等的对象具有相同的hashcode?-如果两个相等的对象有不同的哈希码,它们可能被放置在不同的槽中。-因此,如果您试图使用与插入值相同的键来查找值,那么查找可能会失败。
大部分语言中都是采用对象的内存地址作为默认hashcode