从头认识java-15.7 Map(4)-介绍HashMap的工作原理-hash碰撞(常常作为面试题)
这一章节我们来讨论一下hash碰撞。
1.什么是hash碰撞?
就是两个对象的key的hashcode是一样的,这个时候怎么get他的value呢?
答案是通过equals遍历table那个位置上面的Entry链表。
2.样例
正常的样例:
package com.ray.ch14; import java.util.HashMap; public class Test {
public static void main(String[] args) {
HashMap<Person, Dog> map = new HashMap<Person, Dog>();
Person person_1 = new Person();
person_1.setHeight(180);
person_1.setId(1);
person_1.setName("person_1");
Person person_2 = new Person();
person_2.setHeight(180);
person_2.setId(2);
person_2.setName("person_1");
Dog dog_1 = new Dog();
dog_1.setId(1);
dog_1.setName("dog_1");
Dog dog_2 = new Dog();
dog_2.setId(2);
dog_2.setName("dog_2");
map.put(person_1, dog_1);
map.put(person_2, dog_2);
System.out.println("--" + map.get(person_1).getName());
System.out.println("--" + map.get(person_2).getName());
}
} class Dog {
private int id = 0;
private String name = ""; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public int hashCode() {
System.out.println("dog's hashCode() invoked");
return id;
} @Override
public boolean equals(Object obj) {
System.out.println("dog's equals invokes");
return super.equals(obj);
}
} class Person {
private int id = 0;
private String name = "";
private int height = 0; @Override
public int hashCode() {
System.out.println("person id:" + id + ",hashCode() invoked,"
+ "hashcode:" + this.name.hashCode() + this.height);
return super.hashCode();
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getHeight() {
return height;
} public void setHeight(int height) {
this.height = height;
} @Override
public String toString() {
return "id:" + id + "; Name:" + this.name + "; height:" + this.height;
} @Override
public boolean equals(Object obj) {
System.out.println("id:" + id + ", equals invokes");
return super.equals(obj);
}
}
输出:
person id:1,hashCode() invoked,hashcode:443164103180
person id:2,hashCode() invoked,hashcode:443164103180
person id:1,hashCode() invoked,hashcode:443164103180
--dog_1
person id:2,hashCode() invoked,hashcode:443164103180
--dog_2
解释:
(1)上面建立两个类。然后分别在hashCode和equal方法里面加上输出语句
(2)通过输出能够看到,事实上我们重写的equals方法是没有被调用的。我们仅仅须要通过hashcode就能够定位对应的对象
hash碰撞的代码:
package com.ray.ch14; import java.util.HashMap; public class Test {
public static void main(String[] args) {
HashMap<Person, Dog> map = new HashMap<Person, Dog>();
Person person_1 = new Person();
person_1.setHeight(180);
person_1.setId(1);
person_1.setName("person_1");
Person person_2 = new Person();
person_2.setHeight(180);
person_2.setId(2);
person_2.setName("person_1");
Dog dog_1 = new Dog();
dog_1.setId(1);
dog_1.setName("dog_1");
Dog dog_2 = new Dog();
dog_2.setId(2);
dog_2.setName("dog_2");
map.put(person_1, dog_1);
map.put(person_2, dog_2);
System.out.println("--" + map.get(person_1).getName());
System.out.println("--" + map.get(person_2).getName());
}
} class Dog {
private int id = 0;
private String name = ""; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public int hashCode() {
System.out.println("dog's hashCode() invoked");
return id;
} @Override
public boolean equals(Object obj) {
System.out.println("dog's equals invokes");
return super.equals(obj);
}
} class Person {
private int id = 0;
private String name = "";
private int height = 0; @Override
public int hashCode() {
System.out.println("person id:" + id + ",hashCode() invoked,"
+ "hashcode:" + this.name.hashCode() + this.height);
return this.name.hashCode() + this.height;// 重写的地方
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getHeight() {
return height;
} public void setHeight(int height) {
this.height = height;
} @Override
public String toString() {
return "id:" + id + "; Name:" + this.name + "; height:" + this.height;
} @Override
public boolean equals(Object obj) {
System.out.println("id:" + id + ", equals invokes");
return super.equals(obj);
}
}
输出:
person id:1,hashCode() invoked,hashcode:443164103180
person id:2,hashCode() invoked,hashcode:443164103180
id:2, equals invokes
person id:1,hashCode() invoked,hashcode:443164103180
id:1, equals invokes
--dog_1
person id:2,hashCode() invoked,hashcode:443164103180
--dog_2
解释:
(1)我们重写了Person。也就是key的hashCode方法。人为的产生hash碰撞现象
(2)从输出能够看出,上面的代码须要用到equals方法
回归put和get的源代码。
以下是put的源代码:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
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;
}
以下是get的源代码:
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))//注意的地方
return e.value;
}
return null;
}
大家请注意我上面凝视“注意的地方”:
(1)假设是寻常没有hash碰撞的时候,前面的两个hash比較再加上key的地址的比較就可以。然后后出现“短路”现象,使得后的句子不再运行。
(2)可是在出现hash碰撞的情况下。前面两个条件都成立,然后必须使用最后的equals来推断对象的相等。
3.hash碰撞出现的情景?
(1)通常会出如今大的数据情况之下
(2)hashcode的生成方法唯一性较弱(比方上面的人为的生产hashcode)
总结:这一章节主要通过介绍hash碰撞再一次深入了解HashMap的工作原理。
这一章节就到这里,谢谢。
-----------------------------------
从头认识java-15.7 Map(4)-介绍HashMap的工作原理-hash碰撞(常常作为面试题)的更多相关文章
- 从头认识java-15.7 Map(6)-介绍HashMap的工作原理-装载因子与性能
这一章节我们通过讨论装载因子与性能,再来介绍HashMap的工作原理. 1.什么是装载因子?他有什么作用? 以下的代码就是装载因子 /** * The load factor used when no ...
- 从头认识java-15.7 Map(5)-介绍HashMap的工作原理-Key变了,能不能get出原来的value?(偶尔作为面试题)
这一章节我们讨论一个比較特殊的情况Key变了,能不能get出原来的value? 答案是:有时能够,有时不能够 1.能够的情况: package com.ray.ch14; import java.ut ...
- 从头认识java-15.7 Map(3)-介绍HashMap的工作原理-get方法
接着上一章节.我们来讨论一下get方法. 1.还是利用上一章节的图 下图引用自:http://www.admin10000.com/document/3322.html 我们简单说一下步骤.就是通过h ...
- 【转】Java学习---HashMap的工作原理
[原文]https://www.toutiao.com/i6592560649652404744/ HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都 ...
- Java中的数据结构有哪些?HashMap的工作原理是什么?
Java中常用数据结构 常用的数据结构有哈希表,线性表,链表,java.util包中有三个重要的接口:List,Set,Map常用来实现基本的数据结构 HashMap的工作原理 HashMap基于ha ...
- Java中的HashMap的工作原理是什么?
问答题23 /120 Java中的HashMap的工作原理是什么? 参考答案 Java中的HashMap是以键值对(key-value)的形式存储元素的.HashMap需要一个hash函数,它使用ha ...
- Java HashMap的工作原理(转载)
原文地址:http://www.importnew.com/10620.html 面试的时候经常会遇见诸如:"java中的HashMap是怎么工作的","HashMap的 ...
- [Java] SSH框架笔记_SSH三大框架的工作原理及流程
Hibernate工作原理及为什么要用? 原理:1.通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件2.由hibernate.cfg.x ...
- Java HashMap的工作原理
面试的时候经常会遇见诸如:”java中的HashMap是怎么工作的”.”HashMap的get和put内部的工作原理”这样的问题. 本文将用一个简单的例子来解释下HashMap内部的工作原理. 首先我 ...
随机推荐
- linux一个网卡添加多个虚IP
[root@localhost ~]# ifconfig bond0:0 10.0.0.202 netmask 255.255.255.255 broadcast 10.0.0.255 up 摘自:h ...
- HTML学习----------DAY2第六节
在 HTML 文档中,标题很重要. HTML 标题 标题(Heading)是通过 <h1> - <h6> 等标签进行定义的. <h1> 定义最大的标题.<h6 ...
- HTML学习----------DAY1 第二节
使用 Notepad 或 TextEdit 来编写 HTML 可以使用专业的 HTML 编辑器来编辑 HTML: Adobe Dreamweaver Microsoft Expression Web ...
- centos7;windows下安装和使用spice
感谢朋友支持本博客,欢迎共同探讨交流,因为能力和时间有限,错误之处在所难免,欢迎指正! 假设转载,请保留作者信息. 博客地址:http://blog.csdn.net/qq_21398167 原博文地 ...
- Bloxorz I (poj 3322 水bfs)
Language: Default Bloxorz I Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 5443 Acce ...
- Nginx 代理以及HTTPS (二)
一.HTTPS解析 https 加密 私钥 公钥 http 的握手 是确认网络是连通的. https 的握手 是一个加密的过程 加密图 二. 使用Nginx 部署HTTPS 服务 1.证书生成命令(h ...
- java中replaceAll反斜杠\ or java中replaceAll 括号[
java中replaceAll反斜杠\ String s=new String("this is a \\"); s.replaceAll("\\",&qu ...
- sql 向上取整 向下取整 四舍五入的实例;
SELECT CEILING(23.5/4)'向上取整' ---6 :SELECT FLOOR(23.5/4)'向下取整' ---5 :SELECT ROUND(23.5/4,1)'四舍五入' --5 ...
- 联想 Thinkserver TS250服务器RAID1 重建测试
1.RAID1状态下,拨掉其中一块硬盘后,RAID1即失效. 2.重新插入后,在进行系统后会自动重建 *RAID1 提示Rebuild *进入桌面后软件,显示重建进度 软件下载地址:https://p ...
- git pull 、git fetch、 git clone
git clone 代表从远程克隆过来包括所有的版本信息 git fetch是从远程获取最新的版本 git pull相当于 git fetch 然后再git merge