为什么重写equals方法(为什么重写hashCode方法?)
日常开发中,不会刻意去重写equals和hashCode方法,随着业务代码越写越多,对于这两个方法的记忆就消退了,然而底层知识才能撑起上层建筑,所以拿出来复习下;
这里两个方法都来自于Object;
1.equals:这里equals是一个native方法,返回这个对象的hash code,HashMap受益于该方法;
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
*/
public native int hashCode();
2.hashCode:可以看到equals方法其实就是比较了地址;
public boolean equals(Object obj) {
return (this == obj);
}
辣么,问题来啦,为什么要重写equals?
当我们在比较两个自定义对象是否相等时候,往往是比较他们的字段值是否都相等;而equals本身比较的是地址,创建两个自定义对象,对象被分配在堆中,地址是不同的。所以重写equals方法让对象比较成为了可能;
然后呢?为什么要重写hashCode方法呢?
根据上面源码的注释,我们可以看到,hashCode方法收益与HashMap,这里就从HashMap的put和contains方法来了解:
public V put(K key, V value) {
if (table == EMPTY_TABLE) {
inflateTable(threshold);
}
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry e = table[i];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = https://www.it610.com/article/e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}modCount++;
addEntry(hash, key, value, i);
return null;
}
final int hash(Object k) {
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}h ^= k.hashCode();
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
可以看到这里在存入值得时候,会调用hashCode来获取对应Entry数组所在位置,并循环查找,怎么查找呢?调用了自定义对象的equals方法来查找,这样来实现对Map的操作;
是不是有点小疑问?这里解释一下,两个不同的对象可能hashCode相同,但是绝对不equals,而hashCode的计算效率最高,equals方法还需要去走自己重写的内部逻辑,所以,根据这个特性,先比较hashCode,如果相同,再比较equals,从而提高了HashMap的效率。
而HashMap的contains方法也是如此实现的:
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
final Entry getEntry(Object key) {
if (size == 0) {
return null;
}int hash = (key == null) ? 0 : hash(key);
for (Entry e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
同样,HashSet内部实现就是基于HashMap;
所以:什么场景下需要重写这两个方法呢?
1.使用Set集合操作自定义对象的时候;
2.使用自定义对象作为HashMap的key时(当然很少,而Set就是其中一个实现);
【为什么重写equals方法(为什么重写hashCode方法?)】虽然这些很基础,但都是通往上层的基石;
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 为什么你的路演总会超时()
- 财商智慧课(六)
- 吃了早餐,反而容易饿(为什么?)
- 为什么越花钱的人越有钱,越舍不得花钱的人却越穷()
- dubbo基本认识
- 为什么985/211的学生能胜任工作获得老板的青睐。
- 年轻人,干了孤独这杯酒
- 为什么孩子一定要学会可视化思维!
- tableView|tableView 头视图下拉放大 重写