java-----hashCode和equals的区别
来源:互联网 发布:知乎那些曾经轰动一时 编辑:程序博客网 时间:2024/06/06 01:50
首先来说说两者的区别,接着给出得出这些区别的原因,最后从HashMap和HashSet实现的角度谈谈这两个集合类对hashCode和equals的使用,其实说白了,个人认为这两个区别也只是在HashMap和HashSet中体现的比较明显点;
两者的关系:
(1):两个对象如果equals,那么他们的hashCode也相等
(2):两个对象如果hashCode相等,但他们不一定equals
(3):两个对象hashCode值不等,他们一定不equals
(4):两个对象不equals,他们的hashCode值不一定不等
也就是说我们在判断两个对象等不等的时候,首先判断两者的hashCode值等不等,不等的话两个对象直接就不等了,相等的话再去看equals,这点我们可以从HashMap的使用中体现出来;
首先我们通过实例来具体看下这两者的区别:
首先来印证结论(2):
public class Test {@Overridepublic int hashCode() {System.out.println("执行了hashCode方法");return 1;}@Overridepublic boolean equals(Object obj) {System.out.println("执行了equals方法");return false;}public static void main(String[] args) {HashMap<Test, String> map = new HashMap<>();Test test1 = new Test();Test test2 = new Test();map.put(test1, "test1");map.put(test2, "test2");System.out.println("map的长度: "+map.size());}}在此之前我们有必要看看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 (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; }put方法的实现过程是首先调用hash(key)计算出当前key对应的hash值,在hash(key)方法中会执行当前key对象的hashCode方法,在计算出hash值之后,会调用indexFor算出当前hash值对应要存储到的数组的下标位置,因为HashMap是数组加链表实现的,数组部分就是通过我们key的hash值来对应位置的,而链表部分存储的是hash值相同的所有键值对,indexFor的目的就是找到当前hash值对应的数组下标,有了这个下标之后你会看到一个for循环,他会遍历当前数组下标里面的链表,通过调用key的equals方法来判断当前链表中是否有与将要插入的键值对的key值相同的元素,没有的话,会将当前当前键值对插入到这个链表的表头,如果有的话,则会替换掉原先已经存在的值;
可以看到,put方法首先调用的是hashCode,随后在找到对应hash值在数组中的存储位置之后才会执行equals方法找链表中有没有将要插入的键值对的key值的,为了方便,我们可以这样理解,hashCode找对应hash值在数组中的位置,equals找当前key值在该数组位置相应链表中位置的,直观点就是下面这幅图;
在测试中我们将Test类作为了HashMap的key值,随后调用了HashMap的put方法,接下来我们看看输出结果:
执行了hashCode方法执行了hashCode方法执行了equals方法map的长度: 2第一行的输出是调用map.put(test1, "test1");执行的,第二行的输出是调用map.put(test2, "test2");执行的,因为上面测试中我们让Test类的hashCode方法的返回值都是1,那么此时所有put进map的key的hash值都是相同的,此时在执行map.put(test2, "test2");的时候就需要调用equals方法来查看当前hash值对应的数组位置的链表中有没有与当前key equals的键值对存在,因为我们在Test类中令equals的返回值是false,所以肯定就不存在了,因此map的长度为2;
我们修改上面的测试代码,将Test类中的equals方法的返回值修改为true,也就是修改成如下代码:
public class Test {@Overridepublic int hashCode() {System.out.println("执行了hashCode方法");return 1;}@Overridepublic boolean equals(Object obj) {System.out.println("执行了equals方法");return true;}public static void main(String[] args) {HashMap<Test, String> map = new HashMap<>();Test test1 = new Test();Test test2 = new Test();map.put(test1, "test1");map.put(test2, "test2");System.out.println("map的长度: "+map.size());}}查看输出:
执行了hashCode方法执行了hashCode方法执行了equals方法map的长度: 1不同于上面的测试,这里的map大小变成了1,原因在于我们将equals返回值设置成了true,因为两次put操作hashCode方法返回值是相同的,所以他会执行equals查看当前hash值对应的数组位置处的链表中是否存在于当前key equals的键值对,因为equals始终返回true,那么就是存在了,根据上面对put源码的分析,当前最新的值将替换掉原先的值,不信你可以试试输出key值等于test1或者test2的值,结果都将是"test2";
如果我们把测试代码修改成下面这样:
public class Test {public static int count = 0;@Overridepublic int hashCode() {System.out.println("执行了hashCode方法");count++;return count;}@Overridepublic boolean equals(Object obj) {System.out.println("执行了equals方法");return true;}public static void main(String[] args) {HashMap<Test, String> map = new HashMap<>();Test test1 = new Test();Test test2 = new Test();map.put(test1, "test1");map.put(test2, "test2");System.out.println("map的长度: "+map.size());}}查看输出:
执行了hashCode方法执行了hashCode方法map的长度: 2你会发现根本连equals方法都不会执行,原因在于我们让Test的hashCode方法每次都返回的值都是不一样的,这样两次put方法执行之后key值对应的hash值根本就不相等,也就是他们根本就是存储在数组中的不同下标处了,不会存储到同一下标处当然不用equals方法来查看到底是存储到下标对应处链表的哪个位置了;
从上面的三个测试可以看出来,HashMap在put时候首先调用的是hashCode方法,如果发现当前hash值对应的数组位置处的链表为空的话是不会执行equals的,也就是hashCode方法先于equals方法执行;
- java中hashcode和equals的区别
- java中的hashcode和equals的区别?
- java-----hashCode和equals的区别
- Java中hashCode和equals的区别
- java ==和equals、equals和hashCode的区别
- equals和hashCode的区别
- equals和 hashcode的区别
- equals和hashcode的区别
- equals()和hashCode()的区别
- equals 和hashcode的区别
- java的equals和hashcode方法的区别和联系
- Java中hashCode和equals的区别和作用
- java中hashcode和equals的区别和联系
- java基础-hashCode()和equals()的本质区别和联系
- Java的hashcode()和equals()
- java的equals和hashCode
- JAVA hashCode() 和equals() 区别和作用
- java中的 hashcode() 、equals() 和==的区别
- UVA 10943 HOW do you add?
- 【杭电oj】1013 - Digital Roots(数论 - 九余定理,好题)
- 属性动画步骤总结——包含xml实现与java代码实现
- CDN
- Git 入门 ---- Git 常用命令
- java-----hashCode和equals的区别
- 代码:一种类似outlook资源树的CSS样式
- 死锁浅析
- 《UNIX环境高级编程》--6系统数据文件和信息
- 算是研究生一年级的感慨吧,以后留着自己看
- Hopcroft-karp 算法
- 数据结构学习笔记(五)二叉树及其C++实现
- 通知和代理
- 数据协定