这一章节我们来讨论一下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. Vector源码学习

    安全的可增长数组结构 实现: 1. 内部采用数组的方式. 1.1 添加元素,会每次校验容量是否满足, 扩容规则有两种,1.增加扩容补偿的长度,2.按照现有数组长度翻一倍.容量上限是Integer.MA ...

  2. 今日SGU 6.5

    sgu 160 题意:给你n个数字 数字范围 1 到 m 问你从中取出任意数量的数字使得这些数字的积取模m最大 收获:dp,记录dp的路径 #include<bits/stdc++.h> ...

  3. 题解 P2910 【[USACO08OPEN]寻宝之路Clear And Present Danger】

    说起来这还是本蒟蒻学完Floyd之后做的第一道题. emm...这是一道裸题,题目大致是说有一堆岛,岛之间有海盗,因此每一条边都有一个危险指数(权重),然后给出一段必须经过的路线,求从一号小岛走到N号 ...

  4. QlikView随意改变图例的位置

    组里面花了大价钱请人设计了一套UI的solution,只是是以站点思路设计的报表样式,可是该报表UI设计团队本身因为没有QlikView的背景,因此设计出来的报表不知道能不能再QlikView中实现, ...

  5. MKVToolNix v8.2

    32位版:http://pan.baidu.com/s/1i3s4gGd 64位版: http://pan.baidu.com/s/1gdvqbpp

  6. POJ - 3415 Common Substrings(后缀数组求长度不小于 k 的公共子串的个数+单调栈优化)

    Description A substring of a string T is defined as: T( i, k)= TiTi+1... Ti+k-1, 1≤ i≤ i+k-1≤| T|. G ...

  7. 安装vnc出现的问题

    重启vnc 命令:/sbin/service vncserver start或者vncserver VNC的启动/停止/重启 #service vncserver start/stop/restart ...

  8. Cisco交换机端口安全

    Cisco交换机端口安全       通过端口设置,可以限制允许访问交换机上某个端口的MAC地址以及IP(可选)来实现严格控制对该端口的输入,最终确保网络接入安全.配置网络安全时应该注意如下问题: 1 ...

  9. Android ViewPager实现多个图片水平滚动

    1.示意图                       2.实现分析 (1).xml配置 <!-- 配置container和pager的clipChildren=false, 并且指定margi ...

  10. nodejs-website

    http://docs.nodejitsu.com/articles/file-system/how-to-read-files-in-nodejs http://nodeapi.ucdok.com/ ...