Java-详解HashMap

图片描述

哈希表定义:根据设定的hash函数和处理冲突的方式(开放定址、公共溢出区、链地址、重哈希...)将一组关键字映射到一个有限的连续的地址集上(即bucket数组或桶数组),并以关键字在地址集中的“像”做为记录在表中的存储位置,这种表称为hash表;这一映射过程称为散列,所得存储位置称为哈希地址或散列地址。数组

1、定义

HashMap实现了Map接口,继承AbstractMap。其中Map接口定义了键映射到值的规则,而AbstractMap类提供 Map 接口的骨干实现,以最大限度地减小实现此接口所需的工做。安全

图片描述

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable

2、构造函数

HashMap提供了三个构造函数:数据结构

  • HashMap():构造一个具备默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。函数

  • HashMap(int initialCapacity):构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。性能

  • HashMap(int initialCapacity, float loadFactor):构造一个带指定初始容量和加载因子的空 HashMap。spa

容量表示哈希表中桶的数量,初始容量是建立哈希表时的容量; 装载因子:loadfactor = 表中填入的记录数/哈希表的长度线程

因此loadfactor标志着哈希表的装满程度,直观的看,装载因子越小,发生冲突的几率越小(由于桶中还没装几个数据,就须要扩容),也就是查找性能越好,但同时浪费的空间就变大。相反,装载因子越大,发生冲突的几率越大(等到桶快填满时才能扩容,好比,采用链表法处理冲突,在此种状况下,会致使链表过长),查找性能越差,同时浪费的空间会减小。

3、数据结构

咱们知道在Java中最经常使用的两种结构是数组和模拟指针(引用),几乎全部的数据结构均可以利用这两种来组合实现,HashMap也是如此。实际上HashMap是一个“链表散列”(数组和链表的结合体)。指针

图片描述
可见,HashMap底层实现仍是数组(横行),只是数组的每一项(纵列)都是一条链。Entry为HashMap的内部类,它包含了键key、值value、下一个节点next,以及hash值,这是很是重要的,正是因为Entry才构成了table数组的项为链表。code


总结

*1.HashMap的默认大小为16,即桶数组的默认长度为16;
2.HashMap的默认装载因子是0.75;
3.HashMap内部的桶数组存储的是Entry对象,也就是键值对对象。
4.构造器支持指定初始容量和装载因子,为避免数组扩容带来的性能问题,建议根据需求指定初始容量。装载因子尽可能不要修改,0.75是个比较靠谱的值。
5.桶数组的长度始终是2的整数次方(大于等于指定的初始容量),这样作能够减小冲突几率,提升查找效率。(能够从indexfor函数中看出,h&(length-1),若length为奇数,length-1为偶数那么h&(length-1)结果的最后一位必然为0,也就是说全部键都被散列到数组的偶数下标位置,这样会浪费近一半空间。另外,length为2的整数次方也保证了h&(length-1)与h%length等效).
6.HashMap接受null键;
7.HashMap不容许键重复,可是值是能够重复的。若键重复,那么新值会覆盖旧值。
8.HashMap经过链表法解决冲突问题,每一个Entry都有一个next指针指向下一个Entry,冲突元素(不是键相同,而是hash值相同)会构成一个链表。而且最新插入的键值对始终位于链表首部。
9.当容量超过阈值(threshold)时,会发生扩容,扩容后的数组是原数组的两倍。扩容操做须要开辟新数组,并对原数组中全部键值对从新散列,很是耗时。咱们应该尽可能避免HashMap扩容。
10.HashMap非线程安全。*对象

相关文章
相关标签/搜索