从头认识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内部的工作原理. 首先我 ...
随机推荐
- 使用let's encrypt为你的Ubuntu14+nginx网站保驾护航!
finch最近正在研究一个新的网站系统,闲的没事想搞搞ssl,结果搞了两天,遇到很多问题,现在记录并分享一下经验. 环境之前搭建好了是Ubuntu14+nginx+php5+mysql 现在开始使用l ...
- 【IDEA】Error: java: Compliance level '1.6' is incompatible with target level '1.8'. A compliance level '1.8' or better is required解决办法
在运行的时候常常出现如下错误: Error: java: Compliance level '1.6' is incompatible with target level '1.8'. A compl ...
- 百度地图API的使用示例
刚刚工作的时候写过百度地图API文档,那时候没有记录到技术博客里面,今天在群里看见有个姑娘在问这个问题,重温了一遍,这个API还算好用.百度地图API,集成简单好用,全面,兼容问题,文档全面: 官方文 ...
- 第三讲 $\mathbb{R}^4$上平凡主丛的联络、曲率与Yang-Mills泛函
一. $\mathbb{R}^4$或$\mathbb{R}^n$上平凡主丛的联络与曲率$\newcommand{\R}{\mathbb{R}}$ 回忆切丛$T\R^n\cong \R^n\times\ ...
- 基于Java的开源CMS系统选择
CMS概述 对于网站CMS系统而言,基于PHP的是主流,如Drupal/Joomla在各个主流虚拟机提供商上都是标准配置,也被广泛使用. 但如果你拥有Java团队,或者项目目标是想建立一个企业网使用的 ...
- 洛谷 P1071 潜伏者
P1071 潜伏者 题目描述 R 国和 S 国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动.历尽艰险后,潜伏于 S 国的 R 国间谍小 C 终于摸清了 S 国军用密码的编码规则: 1. S ...
- An internal error occurred during: "Checking tomcat state". Error while reading server.xml
An internal error occurred during: "Checking tomcat state". Error while reading server.xml ...
- 跨域post 及 使用token防止csrf 攻击
环境: 后台使用的python - flask 前台使用angular框架 1.一个跨域post的样例: 跨域post有多种实现方式: 1.CORS:http://blog.csdn.net/hfah ...
- OpenCV【2】---读取png图片显示到QT label上的问题
问题一: 操作图片test.png是一个365x365的PNG图片 通过OpenCV自带的GUI显示出来图像是没问题的,例如以下操作代码所看到的: QStringfileName=QFileD ...
- FSM之三--代码风格
FSM设计之一http://www.cnblogs.com/qiweiwang/archive/2010/11/28/1890244.html Moore型状态机与mealy型状态机相比,由于其状态输 ...