这一章节我们来讨论一下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碰撞(常常作为面试题)的更多相关文章

  1. 从头认识java-15.7 Map(6)-介绍HashMap的工作原理-装载因子与性能

    这一章节我们通过讨论装载因子与性能,再来介绍HashMap的工作原理. 1.什么是装载因子?他有什么作用? 以下的代码就是装载因子 /** * The load factor used when no ...

  2. 从头认识java-15.7 Map(5)-介绍HashMap的工作原理-Key变了,能不能get出原来的value?(偶尔作为面试题)

    这一章节我们讨论一个比較特殊的情况Key变了,能不能get出原来的value? 答案是:有时能够,有时不能够 1.能够的情况: package com.ray.ch14; import java.ut ...

  3. 从头认识java-15.7 Map(3)-介绍HashMap的工作原理-get方法

    接着上一章节.我们来讨论一下get方法. 1.还是利用上一章节的图 下图引用自:http://www.admin10000.com/document/3322.html 我们简单说一下步骤.就是通过h ...

  4. 【转】Java学习---HashMap的工作原理

    [原文]https://www.toutiao.com/i6592560649652404744/ HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都 ...

  5. Java中的数据结构有哪些?HashMap的工作原理是什么?

    Java中常用数据结构 常用的数据结构有哈希表,线性表,链表,java.util包中有三个重要的接口:List,Set,Map常用来实现基本的数据结构 HashMap的工作原理 HashMap基于ha ...

  6. Java中的HashMap的工作原理是什么?

    问答题23 /120 Java中的HashMap的工作原理是什么? 参考答案 Java中的HashMap是以键值对(key-value)的形式存储元素的.HashMap需要一个hash函数,它使用ha ...

  7. Java HashMap的工作原理(转载)

    原文地址:http://www.importnew.com/10620.html 面试的时候经常会遇见诸如:"java中的HashMap是怎么工作的","HashMap的 ...

  8. [Java] SSH框架笔记_SSH三大框架的工作原理及流程

    Hibernate工作原理及为什么要用? 原理:1.通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件2.由hibernate.cfg.x ...

  9. Java HashMap的工作原理

    面试的时候经常会遇见诸如:”java中的HashMap是怎么工作的”.”HashMap的get和put内部的工作原理”这样的问题. 本文将用一个简单的例子来解释下HashMap内部的工作原理. 首先我 ...

随机推荐

  1. vue滚动行为

    有人问道如何记录vue页面的滚动条位置,再次载入组件的时候页面滚动到记录的位置? 思路: 记录滚动条位置我们好记 我们要在组件销毁之前也就是页面跳转的时候 需要用到生命周期beforeDistory将 ...

  2. Mongo集群之主从复制

    上线的系统.数据存储是重要部位.若一个公司的数据库部署还是待用单点部署,那若是宕机或是机器被损坏则是多糟糕的事情呀. 主从复制的部署方式为下图 主从复制是一个简单的数据库同步备份集群技术.这样的方式简 ...

  3. 权重轮询调度算法 java版本号

    权重轮询调度算法(Weighted Round-Robin Scheduling)--java版本号 因为每台server的配置.安装的业务应用等不同.其处理能力会不一样.所以,我们依据server的 ...

  4. swift具体解释之八---------------下标脚本

    swift具体解释之八-----下标脚本 下标脚本 能够定义在类(Class).结构体(structure)和枚举(enumeration)这些目标中.能够觉得是訪问对象.集合或序列的快捷方式.不须要 ...

  5. 百度LBS开放平台个性化地图 制作一款独一无二的地图

    百度LBS开放平台个性化地图  制作一款独一无二的地图 天天用百度地图的亲们是否已不再满足仅仅看例如以下的地图样式了呢? 默认百度地图样式 是否特别渴望看特别不一样的地图呢.如带京城81号气息的午夜蓝 ...

  6. 12.ng-switch

    转自:https://www.cnblogs.com/best/tag/Angular/ 根据作用域表达式动态切换把那个DOM元素包含在已经编译的模板中. 示例代码: <!DOCTYPE htm ...

  7. centos7 出现please make your choice from 1 to enter..

    忘了截图了 刚出现的~~ 输入1 回车 输入q 回车 最后回车 便可以正常启动

  8. Google Nexus 5x Android 7.0 Root

    很久没有写东西了,准备重新养成这个好习惯.因为自己一直在用Nexus,前段时间自己的Nexus5老的不行了,所以买了台5x,一直没时间root,今天有时间终于有时间弄一下. 在这里整理分享一下. 开始 ...

  9. Asp.Net碎知识

    在aspx页面 获取值: UserModel user=new UserModel();实例化 user.Address=context["txtAddress"]; 如果前台不需 ...

  10. 请求由tomcat转到servlet的临界点

    >>>>>>>>>>>>>>>>>>>>>>>>> ...