2021年02月22日java基础第二十一课---Object类
java基础第二十一课---Object类
一、为什么重写equals()方法一定要重写hashCode()方法
1.首先解释equals方法和hashcode方法分别是用来干什么的?
equals()方法:
在Object类源码(如下所示)中,其底层是使用了“==”来实现,也就是说通过比较两个对象的内存地址是否相同判断是否是同一个对象。
public boolean equals(Object obj) {
return (this == obj);
}
- 1
- 2
- 3
但是在实际应用中,该方法不能满足的我们的需求。因为我们认为两个对象即使不是指向的同一块内存,只要这两个对象的各个字段属性值都相同,那么就认为这两个对象是同一个对象。
所以就需要重写equals()方法,即如果两个对象指向内存地址相同或者两个对象各个字段值相同,那么就是同一个对象。
hashCode()方法:
一提到hashcode,很自然就想到哈希表。将某一key值映射到表中的一个位置,从而达到以O(1)的时间复杂度来查询该key值。Object类源码(如下所示)中,hashCode()是一个native方法,哈希值的计算利用的是内存地址。
public native int hashCode();
- 1
hash冲突:
public static void main(String[] args) {
String astring = "Ok";
String bString = new String("Ok");
System.out.println(astring.hashCode());
System.out.println(bString.hashCode());
}
- 1
- 2
- 3
- 4
- 5
- 6
输出:
2556
2556
2.equals()方法和hashCode()方法两者有什么关系?
1.如果两个对象相同(即用equals比较返回true),那么它们的hashCode值一定要相 同!!!!;
2.如果两个对象不同(即用equals比较返回false),那么它们的hashCode值可能相同也可能不同;
3. 如果两个对象的hashCode相同(存在哈希冲突),那么它们可能相同也可能不同(即equals比 较可能是false也可能是true)
4.如果两个对象的hashCode不同,那么他们肯定不同(即用equals比较返回false)
3.最后来看为什么重写equals()就一定要重写hashCode()方法?
对于对象集合的判重,如果一个集合含有100个对象实例,仅仅使用equals()方法的话,那么对于一个对象判重就需要比较4950次,随着集合规模的增大,时间开销是很大的。但是同时使用哈希表的话,就能快速定位到对象的大概存储位置,并且在定位到大概存储位置后,后续比较过程中,如果两个对象的hashCode不相同,也不再需要调用equals()方法,从而大大减少了equals()比较次数。所以从程序实现原理上来讲的话,既需要equals()方法,也需要hashCode()方法。那么既然重写了equals(),那么也要重写hashCode()方法,以保证两者之间的配合关系。
4.两个对象的hashCode()相同,则equals()一定是true对吗?
不一定
hashCode()返回该对象的哈希码值,哈希码值是一个int类型的数字,那么一定会有重复
而在Object当中equals比较的是地址是否相同,所以不一定
基于以上分析,我们可以在Java集合框架中得到验证。由于HashSet是基于HashMap来实现的,所以这里只看HashMap的put方法即可。源码如下
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<K,V> e = table[i]; e != null; e = e.next) {
Object k;
//if语句中,先比较hashcode,再调用equals()比较
//由于“&&”具有短路的功能,只要hashcode不同,也无需再调用equals方法
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
我们在实际应用过程中,如果仅仅重写了equals(),而没有重写hashCode()方法,会出现什么情况?
字段属性值完全相同的两个对象因为hashCode不同,所以在hashmap中的table数组的下标不同,从而这两个对象就会同时存在于集合中,所以重写equals()就一定要重写hashCode()方法。
对于“为什么重写equals()就一定要重写hashCode()方法?”这个问题应该是有个前提,就是你需要用到HashMap,HashSet等Java集合。用不到哈希表的话,其实仅仅重写equals()方法也可以吧。而工作中的场景是常常用到Java集合,所以Java官方建议
重写equals()就一定要重写hashCode()方法。
有道云笔记更精彩O
文档:第二十课—Object类.note