equals() 判断两对象是否相等,hashCode() 计算对象哈希码
都不是 final 方法,都可被重写
使用和重写时,注意
Object 的equals()
public boolean equals(Object obj) {
return (this == obj);
}
Object 实现区分度最高,两对象不是同一个对象, 一定返回 false
equals() 应遵守约定
-
自反:x.equals(x) 必须 true
-
对称:x.equals(y) 与 y.equals(x) 要相等
-
传递:x.equals(y) true,y.equals(z) true,x.equals(z) 必须 true
-
一致:x 和 y 在 equals() 中使用的信息都没有改变,x.equals(y) 值要始终不变
-
非 null:x 不是 null,y 为 null,x.equals(y) 必须 false
Object 的 hashcode()
public native int hashCode();
将对象内存地址作哈希码返回,保证不同对象返回值不同
-
哈希表中起作用
-
如果对象在 equals() 中使用的信息都没有改变,那么 hashCode() 值始终不变
-
如果两个对象使用 equals() 方法判断为相等,则 hashCode() 方法也应该相等
-
如果两个对象使用 equals() 方法判断为不相等,则不要求 hashCode() 也必须不相等;但是开发人员应该认识到,不相等的对象产生不相同的 hashCode 可以提高哈希表的性能
为什么要 hashCode()
插入时通过哈希码直接映射到哈希表中的位置
-
该位置没有对象,直接插入该位置
-
该位置有对象,调 equals() 比较对象是否相等,相等则不需保存;不相等,加入到链表中(jdk8优化为达到链表阀值用红黑树提升性能)
解释了为什么 equals() 相等,则 hashCode() 必须相等
equals()相等,哈希表中只出现一次;如 hashCode()不相等,会散列到哈希表不同位置,哈希表中出现了不止一次
String hashCode()
private final char value[];
private int hash; // Default to 0
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
1、 String 数据是 final 的
String s = "hello";
s = "world";
s = “world” 并不是字符串对象的值变为了 “world”,而是新建了一个 String 对象,s 引用指向了新对象
2、 String 类将 hashCode() 的结果缓存为 hash 字段的值,提高性能
3、 String 对象 equals() 相等的条件是二者同为 String 对象,长度相同,且字符串值完全相同;不要求二者是同一个对象
4、 String 的 hashCode() 计算公式为:s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]
数字 31
-
质数计算哈希码,它与其他数字相乘之后,计算结果唯一的概率更大,哈希冲突的概率更小
-
质数越大,哈希冲突的概率越小,但计算速度也越慢;31 是哈希冲突和性能的折中,经验值
-
JVM 会自动对 31 进行优化:31 * i == (i « 5) - i