从头认识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内部的工作原理. 首先我 ...
随机推荐
- Entity Framework的一个实例
环境:Visual studio2013+sql server本地数据库 创建一个C#应用程序,首先在nuget中添加Entity Framework 接下来的工作分为四个主要部分: 第一部分:App ...
- 删除小脚本 srm
提示:只能删除当前路径下的目录或文件 #!/bin/bash #将测试好的脚本,拷贝到 $PATH 能够搜索到目录下.并且改名 例如: /usr/local/bin cp /test/srm.sh / ...
- 用Python讲述冯绍峰和赵丽颖的爱情故事
昨天刷头条时得知赵丽颖当妈妈了.作为一名程序员突发奇想,不如用Python简单叙述一下冯绍峰和赵丽颖的爱情故事,于是有了本文. 代码十分简单,适合编程小白和有一些Python基础的准程序员,其中用到了 ...
- Java基础学习总结(11)——重载与重写
首先我们来讲讲:重载(Overloading) 一.方法的重载 方法名一样,但参数不一样,这就是重载(overload). 所谓的参数不一样,主要有两点:第一是参数的个数不一样,第二是参数的类型不一样 ...
- URAL 1513. Lemon Tale(简单的递推)
写几组数据就会发现规律了啊. .但是我是竖着看的.. .还找了半天啊... 只是要用高精度来写,水题啊.就当熟悉一下java了啊. num[i] = 2*num[i-1]-num[i-2-k]. 15 ...
- awk条件语句
条件语句用于在运行操作之前做一个測试.在前面的章节中,我们看到了模式匹配规则的一些演示样例. 模式匹配规则本质上就是影响输入循环的条件表达式. 在这一部分,我们主要就在action中所使用的条件语句进 ...
- 參加北京bluemix云计算大会偶记
我就不写散文了.博客也要轻量化. 记录心路历程吧. 这是一次ibm的技术大会.也是传道大会,洗脑大会.会议主题看起来非常多,占领了北京国际饭店的三层,作为一个老ibm bp感受非常多. 1.北京的创业 ...
- 热门游戏<开心消消乐>的“加壳”诡计!!
好久没搞游戏了,前几天看了又又一次看了看<开心消消乐>的1.29最新版..于是故事開始了: 1.反编译分析 首先使用Androidkiller进行反编译,得到两个Smali代码目录:mal ...
- js插件---图片裁剪photoClip
js插件---图片裁剪photoClip 一.总结 一句话总结:页面裁剪图片得到base64格式的图片数据,然后把这个数据通过ajax上传给服务器,服务器将base64图片数据解析成图片并且保存到服务 ...
- 23. Angular 中用 a 标签 href 路由时在浏览器中显示异常 "%2F" 路由失败问题1
这个是angular1.6默认给hash路由上添加了!(感叹号),导致出错,修改方法如下(添加配置,去掉默认前缀感叹号): angular.module('routingDemoApp',['ng ...