写在前边
- 现在的时间:2019-06-05
- 一共讨论两个问题:
hashCode()
方法与euqals()
方法的关系、hashCode()
方法在HashMap等散列的数据结构中有什么作用 - 没有高深的理论,以简单理解为主.
hashCode()
方法与
euqals()
方法的关系
hashCode()
方法与
euqals()
方法的关系
euqals()
方法讲解
- 第一次学Java的时候,有一个重点你肯定知道:比较两个字符串的内容是否相等要用
euqals()
方法,不能用==
. - 所以我们可以这样理解:
euqals()
方法是用来比较两个对象中的内容是否相同的,相同会返回true,不相同返回flase. - 那对象中的内容指的是什么呢,其实就是对象中的属性,对String来说就是字符串的内容了.
- 但如果我们自己定义一个类然后创建两对象,用equals()方法比较这两个属性值一样的对象,结果却会返回false.
- 为什么会这样呢,当对象
p1
调用euqals()方法时,因为它所属的类中并没有重写这个方法,所以会去调用父类中的euqals()方法,也就是Object
中的equals()方法,其源码如下
从源码中可以看出,只有两个对象是同一个对象时,才会返回true,但我们要求只要两个对象的所有属性值相同即返回true.public boolean equals(Object obj) { return (this == obj); }
- 为了达到
只要两个对象的所有属性值相同即返回true
的要求,我们要在People类中重写Object中的equals()方法.
- 那么,为什么String的对象(字符串)调用equals()方法就是比较两个字符串的内容是否相同而不是Object中equals()方法写的比较是否是同一个对象呢,这是因为String类已经重写了equals()方法,其源码如下:
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; }
hashCode()
方法与euqals()
方法的关系
hashCode()
方法会返回一个int值,这个int值就是这个对象对应的哈希值.- 这个方法也存在于Object中,其源代码是
public native int hashCode();
- 就现在所讲的而言,可以这样理解
hashCode()
的作用:这个方法会返回调用它的对象的哈希值,这样就把哈希值与这个对象对应起来了,一个哈希值可能对应着多个对象,但一个对象只对应一个哈希值. hashCode()
与euqals()
有以下关系:- 如果
equals()
为true,说明是同一个对象,那么两个对象的hashCode()
一定相同. - 如果
equals()
为false,说明不是同一个对象,那么两个对象的hashCode()
可能相同也可能不同. - 如果两个对象
hashCode()
相同,则一定是同一个对象,equals()
为true. - 如果两个对象
hashCode()
不同,则可能是同一个对象也可能不是同一个对象,equals()
可能为true,也可能为false.
- 如果
- 可以看到当equals()方法为true时,两个对对象调用hashCode()的值一定相同,所以我们有以下结论:如一个类重写了equals()方法,那么它必须也重写hashCode()方法,否则就会出现equals()为true但hashCode()不同的情况.
hashCode()
方法在HashMap等散列的数据结构中的作用
hashCode()
方法在HashMap等散列的数据结构中的作用
HashMap简单回顾
- HashMap中的数据是以
K-V
的形式存在的. - 数据是无序不可重复的,不可重复指的是
K-V
的K
不可重复. - 如果存入有相同
K
的K-V
数据,那么这条数据的V
会覆盖原来数据的V
.
如何保证不可重复
下边是最通俗的方法,但在Java中并不使用这种方法,这只是为了引出hashCode()的使用而意想出来的.
- 假设现在HashMap中已经有了100条K-V数据.
- 现在要存入一条新的K-V,那么就拿要存入数据的K和每一条数据的K比较,如果遇到相同的就覆盖数据,假如全都不相同,那么存入这条K-V.
- 也就是说用
equals()
方法比较新的K与已存在的K,相同则V覆盖上去,全不相同则K-V存入.
- 也就是说用
- 可见如果要存入这条数据最坏的情况要比较100次,最好的情况要比较1次.
K-V
只存入了V
即要存入的数据覆盖了原来的数据,我们称为存入了数据
K-V
原先K
就不存在K
和V
都存入了,我们也称为存入了数据
使用hashCode()保证不可重复
这是Java使用的方法
- 还是假设HashMap中已经有了100条K-V数据.
- 假设这100个K是:
K1,K2,K3,...,K100
- HashMap会用每个K调用hashCode()方法,计算出每个K的哈希值,前边我们说过
一个哈希值可能对应着多个对象,但一个对象只对应一个哈希值
,所以最后可以形成这样一个表.
哈希值 | 哈希值对应的K |
---|---|
9527 | K1,K34,K22,… |
7855 | K3,K5,K99,… |
7865 | K9,K77,K49,… |
… | … |
- 当我们再要存入一条新的K-V时,HashMap会调用hashCode()计算出新的K-V的K对应的哈希值,然后与表中的哈希值比较.
- 如果有相同的哈希值,那么需要再调用equals()方法比较这个新的K与这个哈希值对应的所有K,因为
hashCode()相同,equals()不一定为false也不一定为true
,如果结果为true
说明原先有个K和新的K相同,新的V覆盖原来的V;如果结果全部为false
,则将K-V存入. - 如果没有相同的哈希值,则直接存入新的K-V,因为
hashCode()不同则equals()一定为false
,则新的K一定不存在
.
- 如果有相同的哈希值,那么需要再调用equals()方法比较这个新的K与这个哈希值对应的所有K,因为
- 可见,要存入数据最好的情况需要比较2次,最坏的情况需要比较
f
(
a
,
b
)
m
a
x
f(a,b)_{max}
f(a,b)max次
- f ( a , b ) = a + b a ∈ [ 1 , 那 个 表 格 的 行 数 ] b ∈ [ 1 , K 值 最 多 的 那 一 行 K 的 个 数 ] f(a,b)=a+b \\ a\in[1,那个表格的行数] \\b\in[1,K值最多的那一行K的个数] f(a,b)=a+ba∈[1,那个表格的行数]b∈[1,K值最多的那一行K的个数]
- 最坏的情况需要比较的次数虽然没办法准确确定,但显示小于原先的100次.
- 如此,使用hashCode(),在存入新的数据时便大大减少了用equals()比较的次数,提高了效率,这便是
hashCode()
在HashMap等散列的数据结构中的作用.