HashMap 是以key-value来存储的数据结构。
底层的实现是:entry类型的数组。将key-value封装成entry对象。对于这种数据结构我们也称之为 散列链表。
HashMap 定义源码如下:
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
{
/**
* The default initial capacity - MUST be a power of two.
*/
//初始最大容量 必须是2的次幂
static final int DEFAULT_INITIAL_CAPACITY = 16;
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
/**
* The load factor used when none specified in constructor.
**/
//负载因子 表示散表的装满程度。
//如HashMap 的size>最大容量 * 0.75;表示HashMap实际容量已满,需要扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* The table, resized as necessary. Length MUST Always be a power of two.
*/
//即是HashMap底层实现: 是以Entry 类型的数组;
transient Entry[] table;
/**
* The number of key-value mappings contained in this identity hash map.
*/
//存储的有效数据 key-value(会被封装成Entry对象) 个数
transient int size;
/**
* The next size value at which to resize (capacity * load factor).
* @serial
*/
//该变量定义作为 该Map是否扩容的依据 ;即是实际容量。
//threshold = 最大容量*负载因子;
//如果size > threshold ;容器将会被扩容2倍,下面会讲到扩容。
int threshold;
HashMap 的构造方法:
//无参构造函数
public HashMap() {
//默认负载因子 0.75
this.loadFactor = DEFAULT_LOAD_FACTOR;
//实际容量 16*0.75
threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
//Entry类型的数组
table = new Entry[DEFAULT_INITIAL_CAPACITY];
init();
}
再来看看 内部定义Entry对象:
static class Entry<K,V> implements Map.Entry<K,V> {
final K key; //hashMap key
V value; //hashMap value
final int hash; //通过对 key.hashCode()的值进行hash运算得出的值
Entry<K,V> next; //下一entry对象的引用。
先看下HashMap的数据结构图:
来看看HashMap put方法:
public V put(K key, V value) {
if (key == null)
//对key==null时处理
return putForNullKey(value);
// 对key的hashCode值进行hash运算
int hash = hash(key.hashCode());
// 得到的hash值与数组长度进行 & (位) 运算
// 得到的i即是数组中对应的下标位置
int i = indexFor(hash, table.length);
//对该entry数组下标为i的位置上entry对象的链表,进行遍历。
//如若存在该数据 则替换原先的value。
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;
}
//key==null的处理,定义一个常量NULL_KEY的Object对象,对它进行hash运算。
private V putForNullKey(V value) {
int hash = hash(NULL_KEY.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
if (e.key == NULL_KEY) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, (K) NULL_KEY, value, i);
return null;
}
//hash运算方法
static int hash(int h) {
return useNewHash ? newHash(h) : oldHash(h);
}
//具体的hash算法
private static int oldHash(int h) {
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
//hash 与 数组长度 & (位)运算。得到数组对应下标的位置
static int indexFor(int h, int length) {
return h & (length-1);
}
void addEntry(int hash, K key, V value, int bucketIndex) {
//提取原先数组下标下的entry对象
//如果该数组下标下没有entry,则e==null
Entry<K,V> e = table[bucketIndex];
//更改数组下标引用至新的entry对象
//并将新的entry对象的next指向数组下标原先的entry对象
//如若该数组下标不存在entry,则next引用为空。
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
//鉴于查找效率的考虑,HashMap 的size > 实际容量时,则扩容。
if (size++ >= threshold)
//entry数组扩容2倍。
resize(2 * table.length);
}
//entry数组扩容2倍
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
//数组扩容后,所有entry元素需要重新计算数组下标位置。
//生成新的散列链表
transfer(newTable);
table = newTable;
//重新计算实际容量
threshold = (int)(newCapacity * loadFactor);
}
//遍历hashMap下所有entry 通过 indexFor 方法重新计算数组位置。
void transfer(Entry[] newTable) {
Entry[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
Entry<K,V> e = src[j];
if (e != null) {
src[j] = null;
do {
Entry<K,V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != null);
}
}
}
HashMap get方法:
//get方法与put方法中处理是否存在该数据是类似的。
public V get(Object key) {
if (key == null)
// key==null的处理
return getForNullKey();
int hash = hash(key.hashCode());
//hash 、indexFor方法确定数组位置上entry的链表,进行遍历。
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;
}
- 大小: 62.3 KB
分享到:
相关推荐
在Java编程中,HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的存储功能,具有快速存取和高效查找的特点。HashMap基于哈希表(也称为散列表)原理,通过键对象的哈希码来定位元素,进而实现O(1)...
### Java中HashMap, LinkedHashMap, TreeMap,HashTable的区别 在Java编程语言中,`Map`接口是集合框架中的一个重要组成部分,用于存储键值对。本文将详细分析四种常用的`Map`实现类:`HashMap`, `LinkedHashMap`, ...
Java中的HashMap是一种基于散列机制的Map接口的实现,它允许我们存储键值对。键是唯一的,而值可以重复。HashMap在处理数据时非常高效,因为其操作的时间复杂度接近于O(1)。这是通过使用散列函数将键映射到相应的...
在Java中,HashMap是一种广泛使用的数据结构,它基于哈希表的Map接口实现。哈希表是一种通过哈希过程将键映射到特定位置的数据结构,该位置存储了键对应的值。在详细探讨Java中HashMap的工作机制之前,首先需要理解...
结合Java的HashMap中的一些优点,改进了C++ 的hash_map。 详细说明见我的博客:http://blog.csdn.net/mdj67887500/article/details/6907702
Java的HashMap是一个基于哈希表的Map接口实现,提供快速的插入、删除和查找操作,平均时间复杂度为O(1)。下面我们将详细探讨JavaScript中如何实现类似Java HashMap的功能,以及这个实现可能包含的关键知识点。 1. *...
Map a = new HashMap(); //方法一 Iterator it = a.entrySet().iterator(); while (it.hasNext()) { Map.Entry pairs = (Map.Entry) it.next(); System.out.println(pairs.getValue()); } //以下方法需要jdk5以上...
Java HashMap 类详解 本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点。 1. HashMap 和 HashSet 的关系 HashMap 和 HashSet 是 Java Collection Framework ...
《java编程思想》,Map结合HashMap获取键相关联的值
在Java编程语言中,`HashMap`是`java.util`包中的一个核心类,它属于集合框架的一部分,主要用于存储键值对的数据结构。`HashMap`基于哈希表(散列表)实现,提供了快速的插入、删除和查找操作,平均时间复杂度为O(1...
在Java中,我们通常使用HashMap、ConcurrentHashMap等Map实现来创建缓存。这些数据结构具有O(1)的平均时间复杂度,能够快速地查找和存储元素,非常适合缓存应用场景。 在给定的描述中提到了"毫秒计算",这涉及到...
Map接口则是Java集合框架的一部分,它提供了键值对的数据存储方式,方便数据的存取。将Pojo对象转换为Map,可以简化数据处理过程,尤其是在JSP页面上展示数据时,Map的灵活性更加突出。本文将详细介绍如何实现Java中...
在Java中,HashMap广泛应用于Set、Map等容器中,用于快速根据Key找到元素。例如,Set的contains方法和Map的get方法都是通过Key去查找的。 然而,HashMap的实现也存在一些问题,例如哈希碰撞问题和equals方法的调用...
在Java编程中,Map接口是用于存储键值对的数据结构,而Java提供了多种Map的实现,包括TreeMap、HashMap和ConcurrentSkipListMap。本文主要比较了这三种Map的性能,尤其是在插入和查找操作上的效率。 1. **TreeMap**...
在Java编程中,HashMap是Java集合框架中的一个重要成员,它提供了高效的存储和检索对象的机制。在Java 8中,HashMap有一些重要的优化和改进,尤其是对于键(Key)的处理方式。这里我们将深入探讨Java 8 HashMap如何...
java Map实现的cache manager,定时清除缓存里面的值,使数据一致保持最新
java hashmap 扩容因子为什么是0.75,官方给出的解释
Java 在 HashMap 初始化时赋初值过程解析 Java 中的 HashMap 是一种常用的数据结构,一般用来做数据字典或者 Hash 查找的容器。在初始化并赋初值时,我们通常使用 `HashMap, Object> map = new HashMap();` 的方式...
Java中的HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的高效存储和访问。HashMap基于哈希表(也称为散列表)原理工作,它允许用户通过键(Key)快速查找对应的值(Value)。在HashMap中,键和值...
"Java中HashMap容量的初始化实现" Java中HashMap容量的初始化实现是非常重要的,特别是在大规模数据处理时。HashMap的容量初始化可以极大地影响程序的性能。在本文中,我们将详细介绍Java中HashMap容量的初始化实现...