HashMap原理

1.HashMap的数据结构

  数组的特点是:寻址容易,插入和删除困难;而链表的特点是:寻址困难,插入和删除容易。那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表,哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法—— 拉链法,我们可以理解为“链表的数组” ,如图:

  从上图我们可以发现哈希表是由数组+链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。

  HashMap其实也是一个线性的数组实现的,所以可以理解为其存储数据的容器就是一个线性数组。这可能让我们很不解,一个线性的数组怎么实现按键值对来存取数据呢?这里HashMap有做一些处理。

  1.首先HashMap里面实现一个静态内部类Entry,其重要的属性有 key , value, next,从属性key,value我们就能很明显的看出来Entry就是HashMap键值对实现的一个基础bean,我们上面说到HashMap的基础就是一个线性数组,这个数组就是Entry[],Map里面的内容都保存在Entry[]里面。

2.HashMap的存取实现

既然是线性数组,为什么能随机存取?这里HashMap用了一个小算法,大致是这样实现:

1 //存储时:
2 int hash = key.hashCode();// 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值
3 int index = hash % Entry[].length;
4 Entry[index] = value;
5
6 //取值时:
7 int hash = key.hashCode();
8 int index = hash % Entry[].length;
9 return Entry[index];

到这里我们轻松的理解了HashMap通过键值对实现存取的基本原理

3.疑问:如果两个key通过hash%Entry[].length得到的index相同,会不会有覆盖的危险?

  这里HashMap里面用到链式数据结构的一个概念。上面我们提到过Entry类里面有一个next属性,作用是指向下一个Entry。打个比方, 第一个键值对A进来,通过计算其key的hash得到的index=0,记做:Entry[0] = A。一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next = A,Entry[0] = B,如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方其实存取了A,B,C三个键值对,他们通过next这个属性链接在一起。所以疑问不用担心。也就是说数组中存储的是最后插入的元素。到这里为止,HashMap的大致实现,我们应该已经清楚了。

  当然HashMap里面也包含一些优化方面的实现,这里也说一下。比如:Entry[]的长度一定后,随着map里面数据的越来越长,这样同一个index的链就会很长,会不会影响性能?HashMap里面设置一个因素(也称为因子),随着map的size越来越大,Entry[]会以一定的规则加长长度。

3.解决hash冲突的办法

  1. 开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)
  2. 再哈希法
  3. 链地址法
  4. 建立一个公共溢出区

Java中hashmap的解决办法就是采用的链地址法。

4.实现自己的HashMap

  MapTest.java

 1 package General;
 2 import java.util.*;
 3 public class MapTest {
 4     public static void main(String[] args){
 5         Map<String,Employee> staff=new HashMap<>();
 6         staff.put("144-25-5456",new Employee("Amy Lee"));
 7         staff.put("567-24-2456",new Employee("Harry Hacker"));
 8         staff.put("157-62-7935",new Employee("Gary Cooper"));
 9         staff.put("465-62-5537",new Employee("Francesca Cruz"));
10
11         //print all entries
12         System.out.println(staff);
13
14         //remove an entry
15         staff.remove("567-24-2456");
16
17         //replace an entry
18         staff.put("456-62-5527",new Employee("Francesca Miller"));
19
20         //look up a value
21         System.out.println(staff.get("157-62-7935"));
22
23         //iterate through all entries
24         for(Map.Entry<String, Employee>entry:staff.entrySet()){
25                 String key=entry.getKey();
26                 Employee value=entry.getValue();
27                 System.out.println("Key="+key+", value="+value);
28         }
29     }
30 }
31 class Employee{
32     private String name;
33     public Employee(String n){
34         name=n;
35     }
36     public String getName(){
37         return name;
38     }
39 }

1 {157-62-7935=Amy Lee,
2 567-24-2456=Harry Hacker,
3 144-25-5456=Gary Cooper,
4 465-62-5537=Francesca Cruz}
5 Francesca Miller
6 Key=157-62-7935, value=Amy Lee
7 Key=144-25-5456, value=Harry Hacker
8 Key=465-62-5537, value=Gary Cooper
9 Key=456-62-5527, value=Francesca Cruz

时间: 2024-10-23 11:28:02

HashMap原理的相关文章

MapDemo1+2 Map接口的常用方法及遍历 及HashMap原理

MapDemo1 Map接口的常用方法 /** * java.util * Map接口<K,V> 类型参数: K - 此映射所维护的键的类型 V - 映射值的类型 定义: Map是一个接口,又称作查找表 java提供了一组可以以键值对(key-value)的形式存储数据的数据结构, 这种数据结构成为Map.我们可以看成是一个多行两列的表格,一列是存放key,一列存放value. 而每一行就相当于一组 key-value对,表示一组数据. 注意: 1.Map对存入元素有一个要求,就是key不能重

(柯昌合)HashMap原理(柯昌合)

了解HashMap原理对于日后的缓存机制多少有些认识.在网络中也有很多方面的帖子,但是很多都是轻描淡写,很少有把握的比较准确的信息,在这里试着不妨说解一二. 对于HashMap主要以键值(key-value)的方式来体现,笼统的说就是采用key值的哈希算法来,外加取余最终获取索引,而这个索引可以认定是一种地址,既而把相应的value存储在地址指向内容中.这样说或许比较概念化,也可能复述不够清楚,来看列式更加清晰: int   hash=key.hashCode();//-------------

HashMap原理阅读

HashMap原理阅读 原文地址:https://www.cnblogs.com/liang-zisong/p/8480071.html

HashMap原理(二) 扩容机制及存取原理

我们在上一个章节<HashMap原理(一) 概念和底层架构>中讲解了HashMap的存储数据结构以及常用的概念及变量,包括capacity容量,threshold变量和loadFactor变量等.本章主要讲解HashMap的扩容机制及存取原理. 先回顾一下基本概念: table变量:HashMap的底层数据结构,是Node类的实体数组,用于保存key-value对: capacity:并不是一个成员变量,但却是一个必须要知道的概念,表示容量: size变量:表示已存储的HashMap的key-

HashMap原理详解

HashMap 一 定义和创建 HashMap实现了Map接口,继承AbstractMap类.AbstractMap中包含了map的基本功能. (1) 初始大小 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 从源码可以看出大小是16(1左移动4位1000 = 16) static final int MAXIMUM_CAPACITY = 1 << 30; 最大长度是2的30次方1073741824 基本能

HashMap原理解析

今天花了一天的时间敲代码查资料查阅了java 7 的HashMap的工作原理,java 8 的hashMap 代码更为复杂,一下是java 7的原理: put 方法 1.首先对key 值进行null 验证,如果为null,则把元素存储到Entry<k,v>数组的一个元素中,返回null,因为null 的哈希值是0. 2.然后调用hash 方法计算hash 值 会调用对象的hashCode 方法 3.调用indexFor 根据hash 值获取table 准确的位置 4.遍历准确找到数组中的链表.

【数据结构】HashMap原理及实现学习总结

HashMap是Java中最常用的集合类框架之一,是Java语言中非常典型的数据结构.本篇主要是从HashMap的工作原理,数据结构分析,HashMap存储和读取几个方面对其进行学习总结.关于HashMap的完整源码分析请查看下一篇. 一. HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象.当获取

HashMap 原理分析

HashMap中key的存放原理: 1.创建Set集合 HashSet 其容器数组默认大小为16 也就是将容器分为16个区域,每一个区域存放的是链表. 2.现有一个元素想存放到set集合中,第一步要确定要放在哪个区域里面.方法是先取元素的hashcode,将这个值与1111进行与运算 所得到的值一定是0~15之间的数,这个数字决定了该元素会存放在set集合中的哪个区域里面. 3.已经决定了存放在那个区域,就检查这个区域的使用情况,如果该区域没有任何元素,就将新元素直接放置在这个区域中. 4.如果

HashMap原理与优化

参考文献: HashMap的工作原理 java中HashMap重要性质和优化总结 一.HashMap的基本了解 基本定义:根据源代码的描述可知,HashMap是基于哈希表的Map接口的实现,其包含了Map接口的所有映射操作,并且允许使用null键和null值. 与HashTable的区别:HashMap可以近似地看成是HashTable,但是它是非线程安全的,并且允许使用null键和null值,而这些都与HashTable恰巧相反.注:HashMap可以使用ConcurrentHashMap代替

细说java系列之HashMap原理

类图 在正式分析HashMap实现原理之前,先来看看其类图. 源码解读 下面集合HashMap的put(K key, V value)方法探究其实现原理. // 在HashMap内部用于存放插入数据的是一个名为"table"的一维Node对象数组 // Node对象为实际存放插入数据Key和Value的数据结构 transient Node<K,V>[] table; // 外部调用插入数据的接口方法 public V put(K key, V value) { retur