这一章节我们来讨论一下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的工作原理。

这一章节就到这里,谢谢。

-----------------------------------

文件夹

最新文章

  1. 在Hibernate框架中详谈一级缓存
  2. java/python中的队列
  3. 走进AngularJs(三)自定义指令-----(上)
  4. Windows Azure Azure 简介
  5. DICOM医学图像处理:DIMSE消息发送与接收“大同小异”之DCMTK fo-dicom mDCM
  6. [CSS] Make element not selectable
  7. linux常用命令(查看某些软件是否已安装)
  8. Selenium-Grid工作方式
  9. Problem C: 求个最大值
  10. 早期Swift中Cocos2D初始化代码的重构
  11. css3新特性总结
  12. 洛谷P4592 [TJOI2018]异或(可持久化01Trie)
  13. 网络流Dinic算法
  14. [Web 前端] Jquery 复制元素,并修改属性, 追加到另一个元素后面
  15. js-之NaN和isNaN
  16. 福大软工 Alpha 事后诸葛亮
  17. KETTLE:mongdb与mysql互传数据
  18. angularJS directive中的controller和link function辨析
  19. Linux命令应用大词典-第17章 软件包管理
  20. ui-grid样式,表格高度自适应行高,没有滚动条,去掉表头

热门文章

  1. Spring MVC框架一个实例的手动实现
  2. Redis-Sentinel原理及配置详解【转】
  3. 统计 MapReduce 输出路径修改。
  4. docker安装cloudera manager,切换cloudera-scm用户报错can not open session
  5. hadoop1.0.3学习笔记
  6. 【iOS开发-34】自己主动释放池@autoreleasepool的使用注意事项以及ARC机制——面试必考内容
  7. MAC 文件加密
  8. Codeforces Round #337 (Div. 2) 610C Harmony Analysis(脑洞)
  9. 两天学会DirectX 3D之入门
  10. 由安装两块网卡的linux系统中引起网络不通想到的