- 浏览: 210850 次
- 性别:
- 来自: 哈尔滨
文章分类
- 全部博客 (267)
- java.lang (8)
- 问题汇总 (21)
- 异常记录 (20)
- 功能实现 (19)
- 面试总结 (25)
- 技巧总结 (8)
- 常用代码 (4)
- 编程习惯 (3)
- 编码规则 (3)
- java.util (10)
- java.io (1)
- JavaWeb (9)
- MySQL (16)
- SVN (3)
- MyBatis (11)
- Velocity (7)
- 其他知识 (10)
- 人生哲理 (1)
- 人生故事 (1)
- 自我感悟 (1)
- shiro (3)
- 基础知识 (0)
- 问题总结 (1)
- Spring 标签 (1)
- Spring (3)
- 点滴生活 (1)
- DOS (1)
- CAS (4)
- Linux (9)
- Storm (6)
- Shell (1)
- regex (1)
- Collection (4)
- poi (1)
- 经典语句 (1)
- NIO (5)
- concurrent (14)
- RPC (1)
- zookeeper (3)
- 待整理 (2)
- Hadoop (9)
- RabbitMq (2)
- flume (1)
- hive (7)
- hbase (4)
- kafka (1)
- scala (1)
- GC (0)
- java.util.concurrent.atomic (1)
- java.lang.ref (6)
- JVM (2)
- algorithm (1)
- conception (1)
- java key word (1)
- sun.misc (1)
最新评论
HashMap jdk-1.8.0
一、总结
- 允许key = null
- put时,hash散列值相同的元素,放在Entry 的首位置上
- 数组扩容,length*2
- 链表扩容,一个链转变为红黑树
- Map m = Collections.synchronizedMap(new HashMap(...)); 线程安全
- ConcurrentHashMap 线程安全
二、成员变量
1.源码
/** * The default initial capacity - MUST be a power of two. */ // 默认的初始化容量大小,一定是2的N幂 2^N 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. */ // 最大的容量,一定要是2^N的形式 且小于 2^30 static final int MAXIMUM_CAPACITY = 1 << 30; /** * The load factor used when none specified in constructor. */ // 默认的负载因子 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 map. */ // hashMap中key-value对的数量 // transient 不可序列化 transient int size; /** * The next size value at which to resize (capacity * load factor). * @serial */ // threshold = capacity * load factor ; 边界值, // 当新增元素后的Map.size >= threshold , hashMap 进行扩容操作 int threshold; /** * The load factor for the hash table. * * @serial */ // 负载因子,final 修饰,内容不可变更 final float loadFactor; /** * The number of times this HashMap has been structurally modified * Structural modifications are those that change the number of mappings in * the HashMap or otherwise modify its internal structure (e.g., * rehash). This field is used to make iterators on Collection-views of * the HashMap fail-fast. (See ConcurrentModificationException). */ // hashMap 被修改的次数,volatile 线程间可见,防止多个线程同时对一个hashMap进 // 行操作,抛出异常 transient volatile int modCount;
三、构造方法
1.1源码
/** * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and load factor. * * @param initialCapacity the initial capacity * @param loadFactor the load factor * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ public HashMap(int initialCapacity, float loadFactor) { // 初始化hashMap的容量大小 if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); // hashMap 的最大容量 2^30 if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; // 负载因子:小于0 或者 不是一个 数值 if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); // 数组的大小,一定是一个 2^N次幂的形式 // Find a power of 2 >= initialCapacity int capacity = 1; while (capacity < initialCapacity) capacity <<= 1; // 1 向左移动一位,与当前的初始化的大小进行比较;如果小于,继续移位 // 初始化时,可以直接定义为 2^N 次幂 this.loadFactor = loadFactor; // 计算边界值,如果新增数据后 size > threshold 则扩充 threshold = (int)(capacity * loadFactor); table = new Entry[capacity]; // 初始化 init(); }
1.2.分析
1.2.1
Float.isNaN()
1.2.2 init()
方法体内无任务实现,是给子类提供的,如 LinkedHashMap 继承 HashMap 并覆盖重写了此方法
2.
/** * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and the default load factor (0.75). * * @param initialCapacity the initial capacity. * @throws IllegalArgumentExcepti[/ur[/url]l]on if the initial capacity is negative. */ // 根据指定的容量初始化 public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR); } /** * Constructs an empty <tt>HashMap</tt> with the default initial capacity * (16) and the default load factor (0.75). */ // 默认的构造方法 public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // 0.75 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); // 16*0.75 table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); }
3.源码
/** * Constructs a new <tt>HashMap</tt> with the same mappings as the * specified <tt>Map</tt>. The <tt>HashMap</tt> is created with * default load factor (0.75) and an initial capacity sufficient to * hold the mappings in the specified <tt>Map</tt>. * * @param m the map whose mappings are to be placed in this map * @throws NullPointerException if the specified map is null */ // 根据已有的Map初始化 public HashMap(Map<? extends K, ? extends V> m) { // 容量大小: m.size / 0.75 + 1 与 16 取最大值 this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); putAllForCreate(m); } // 遍历Map private void putAllForCreate(Map<? extends K, ? extends V> m) { for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { Map.Entry<? extends K, ? extends V> e = i.next(); putForCreate(e.getKey(), e.getValue()); } } /** * This method is used instead of put by constructors and * pseudoconstructors (clone, readObject). It does not resize the table, * check for comodification, etc. It calls createEntry rather than * addEntry. */ private void putForCreate(K key, V value) { // 判断key 是否为 null 若是,则放在 数组 0 的位置上 // 否则,进行二次hash计算 int hash = (key == null) ? 0 : hash(key.hashCode()); // hash % length 确定数据存放在数组中的位置 int i = indexFor(hash, table.length); /** * Look for preexisting entry for key. This will never happen for * clone or deserialize. It will only happen for construction if the * input Map is a sorted map whose ordering is inconsistent w/ equals. */ for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && // key 已存在,返回原有的value值,并替换为新值 ((k = e.key) == key || (key != null && key.equals(k)))) { e.value = value; return; } } createEntry(hash, key, value, i); } /** * Like addEntry except that this version is used when creating entries * as part of Map construction or "pseudo-construction" (cloning, * deserialization). This version needn't worry about resizing the table. * * Subclass overrides this to alter the behavior of HashMap(Map), * clone, and readObject. */ void createEntry(int hash, K key, V value, int bucketIndex) { // bucketIndex 数组中存放该数据的位置 // 取出该位置的原有的链表 Entry<K,V> e = table[bucketIndex]; // 生成新的链表 // Entry 的构造方法 // 将原有的链表数据放在新加入的Entry 的链接的next位置上 // 新加入的数据在链表的首位 table[bucketIndex] = new Entry<K,V>(hash, key, value, e); // size 表示 map 中 key - value 对的数量 size++; }
四、get
1.源码
public V get(Object key) { // hashMap允许key = null .将所有key = null 的放在数组0 的位置上 if (key == null) // 去数组第0个位置上查找 return getForNullKey(); // 计算hash数值 int hash = hash(key.hashCode()); // 取出 hash值对应的数组中的位置 // 遍历此位置下的链表,是否有与key相等的值;有则返回value,无返回null 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; }
/** * Offloaded version of get() to look up null keys. Null keys map * to index 0. This null case is split out into separate methods * for the sake of performance in the two most commonly used * operations (get and put), but incorporated with conditionals in * others. */ // 取出 key = null 的数组第0个位置上的链表,若非空,则返回此处的value private V getForNullKey() { for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) return e.value; } return null; }
/** * Applies a supplemental hash function to a given hashCode, which * defends against poor quality hash functions. This is critical * because HashMap uses power-of-two length hash tables, that * otherwise encounter collisions for hashCodes that do not differ * in lower bits. Note: Null keys always map to hash 0, thus index 0. */ // hash 二次计算 static int hash(int h) { // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor). h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
/** * Returns index for hash code h. */ // 计算后的hash值与当前数组的长度取余 static int indexFor(int h, int length) { return h & (length-1); }
五、containsKey()
/** * Returns <tt>true</tt> if this map contains a mapping for the * specified key. * * @param key The key whose presence in this map is to be tested * @return <tt>true</tt> if this map contains a mapping for the specified * key. */ // 当前map 中是否包含 某个 key 值 public boolean containsKey(Object key) { return getEntry(key) != null; } /** * Returns the entry associated with the specified key in the * HashMap. Returns null if the HashMap contains no mapping * for the key. */ // 判断当前的key是否为null,若是,hash = 0 ;否则,计算hash值 final Entry<K,V> getEntry(Object key) { int hash = (key == null) ? 0 : hash(key.hashCode()); // 获取 hash % length 位置处的数组,遍历链表 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 != null && key.equals(k)))) return e; } return null; }
六、put
1.源码
/** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V put(K key, V value) { // hashMap 允许 key = null // 判断 key == null ,若是 ,放在 数组 0 的位置上 if (key == null) return putForNullKey(value); // 跟组 key 的hash值再次计算 hash int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); // 确认存放位置 hash % length for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; // 判断当前的 key 是否已存在,若是,返回 value 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; }
/** * Offloaded version of put for null keys */ private V putForNullKey(V value) { // 取出 数组 0 位置处的链表,判断链表是否已有值,若有,替换value,返回 // 原有的 value for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } // 新增value modCount++; addEntry(0, null, value, 0); return null; }
/** * Adds a new entry with the specified key, value and hash code to * the specified bucket. It is the responsibility of this * method to resize the table if appropriate. * * Subclass overrides this to alter the behavior of put method. */ // 增加数组 // hash 表示 key 的hash值 // key value 为需要加入的数据 // buketIndex 数组的下标位置 void addEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; // Entry<K,V> 构造方法,四个成员变量 table[bucketIndex] = new Entry<K,V>(hash, key, value, e); if (size++ >= threshold) // 扩容:当前数组长度的2倍 resize(2 * table.length); }
/** * Creates new entry. */ // 新加入的链表的值,放在链表的首位,将原有的链表作为新加入值的next Entry(int h, K k, V v, Entry<K,V> n) { value = v; next = n; key = k; hash = h; }
/** * Rehashes the contents of this map into a new array with a * larger capacity. This method is called automatically when the * number of keys in this map reaches its threshold. * * If current capacity is MAXIMUM_CAPACITY, this method does not * resize the map, but sets threshold to Integer.MAX_VALUE. * This has the effect of preventing future calls. * * @param newCapacity the new capacity, MUST be a power of two; * must be greater than current capacity unless current * capacity is MAXIMUM_CAPACITY (in which case value * is irrelevant). */ // 数组扩容,当 size > threshold = init 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]; // 数组重新定位存储位置 transfer(newTable); table = newTable; // 新的负载因子 threshold = (int)(newCapacity * loadFactor); }
/** * Transfers all entries from current table to newTable. */ void transfer(Entry[] newTable) { // 将数组赋值给src,不对原数组进行变更 Entry[] src = table; int newCapacity = newTable.length; for (int j = 0; j < src.length; j++) { // 取出原数据中 j 位置的数据 Entry<K,V> e = src[j]; if (e != null) { // 释放存储空间 src[j] = null; do { // 原链表的 e.next Entry<K,V> next = e.next; // 新数组中的存放位置 int i = indexFor(e.hash, newCapacity); // 原链表的 e.next 指向 新数组中的 i 处的链表 e.next = newTable[i]; // 将 原链表的 e 赋值给 新的链表 newTable[i] = e; // 原链表的指针下移 e = next; // 处理结果,新的链表中的数据是原链表中数据的倒置 } while (e != null); } } }
扩容,将原数组中的数据拷贝到新的数组中
2.总结
modCount 记录当前操作此Map的次数
在 对map进行迭代处理时,会记录操作的次数,当modCount 与 期望的操作次数不同时,抛出
throw new ConcurrentModificationException();
七.remove
1.源码
/** * Removes the mapping for the specified key from this map if present. * * @param key key whose mapping is to be removed from the map * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V remove(Object key) { Entry<K,V> e = removeEntryForKey(key); return (e == null ? null : e.value); } /** * Removes and returns the entry associated with the specified key * in the HashMap. Returns null if the HashMap contains no mapping * for this key. */ final Entry<K,V> removeEntryForKey(Object key) { // 计算 hash 值 int hash = (key == null) ? 0 : hash(key.hashCode()); // 定位数组中位置 int i = indexFor(hash, table.length); // 当前的数组中的链表 Entry<K,V> prev = table[i]; Entry<K,V> e = prev; while (e != null) { // 非空 Entry<K,V> next = e.next; Object k; // 获取数组i位置处的链表,遍历此链表 // 若key在链表首位,则将 e 直接指向 e.next // 若key不在链表首位,prev.next = next if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; // 操作次数,fast fail size--; if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; // 链表指针下移 } return e; }
八、clone
1.源码
/** * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and * values themselves are not cloned. * * @return a shallow copy of this map */ public Object clone() { HashMap<K,V> result = null; try { result = (HashMap<K,V>)super.clone(); } catch (CloneNotSupportedException e) { // assert false; } result.table = new Entry[table.length]; result.entrySet = null; result.modCount = 0; result.size = 0; result.init(); result.putAllForCreate(this); return result; }
2.分析
对当前map 的 拷贝,包括值
九、modCount 快速失败
1.示例
Map<String,String> map = new HashMap<String,String>(); map.put("1", "1"); map.put("2", "1"); map.put("3", "1"); map.put("4", "1"); map.put("5", "1"); Iterator<String> iterator = map.keySet().iterator(); while(iterator.hasNext()){ String next = iterator.next(); map.put("6", "5"); }
2.分析
快速失败 modCount 记录当前的线程对此集合的操作次数,迭代前,将 modCount 赋值给 expectedCount ,在迭代过程中如果 modCount 发生变更,则说明有其他线程在对此 map 进行操作
3.源码
private abstract class HashIterator<E> implements Iterator<E> { Entry<K,V> next; // next entry to return int expectedModCount; // For fast-fail int index; // current slot Entry<K,V> current; // current entry HashIterator() { expectedModCount = modCount; if (size > 0) { // advance to first entry Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } } public final boolean hasNext() { return next != null; } final Entry<K,V> nextEntry() { // 此处判断,失败 if (modCount != expectedModCount) throw new ConcurrentModificationException(); Entry<K,V> e = next; if (e == null) throw new NoSuchElementException(); if ((next = e.next) == null) { Entry[] t = table; while (index < t.length && (next = t[index++]) == null) ; } current = e; return e; } }
HashMap分析
扩容机制
发表评论
-
Arrays
2017-10-27 22:54 355Arrays 一、总结 1.基于 jdk 1.8 二、a ... -
Collections
2017-10-27 22:40 395Collections 一、总结 1.基于 JDK 1.8 ... -
LinkedList
2017-10-09 21:18 434LinkedList 一、总结 1.基 ... -
Objects
2017-10-08 12:20 402Objects 一、总结 二、equals Obje ... -
RandomAccess
2017-10-08 11:24 388RandomAccess 总结: 1.基于 JDK 1.8 ... -
ArrayList
2017-10-08 10:14 448ArrayList 一、总结 1.基于 JDK 1.8 源 ... -
HashSet
2017-09-24 15:04 346HashSet 一、总结(jdk 1.8.0_131) 1 ... -
HashTable
2017-09-23 20:54 371Hashtable 一、对比HashMap 1. 项目Ha ... -
Vector
2017-03-11 14:57 505Vector 一、总结 1.线程安全 二、类 1.源 ...
相关推荐
HashMap之resize()方法源码解读 HashMap的resize()方法是HashMap中最核心的方法之一,该方法负责扩容HashMap的容量,以便存储更多的键值对。下面我们将对HashMap的resize()方法进行源码解读,了解其扩容机制和原理...
《HashMap面试题详解》 HashMap作为Java集合框架中的重要成员,是面试中常见的知识点,尤其在数据结构与算法、并发编程以及JVM内存管理等领域,HashMap的深入理解至关重要。本篇将围绕HashMap的相关面试题,从基础...
### hashMap和hashTable的区别 #### 一、简介与基本概念 `HashMap` 和 `HashTable` 都是 Java 集合框架中非常重要的数据结构,它们都实现了 `Map` 接口,用于存储键值对。尽管它们在功能上有很多相似之处,但在...
在Java编程中,HashMap是一个非常常用的集合类,用于存储键值对数据。然而,它存在一个重要的特性,那就是线程不安全。理解这个问题并找到解决方案是每个Java开发者必须掌握的知识。 HashMap线程不安全的原因主要...
### HashMap与HashTable的区别详解 #### 引言 在Java编程中,`HashMap`与`HashTable`作为两种常用的数据结构,经常被用来存储键值对数据。尽管它们在功能上相似,但在实现细节、性能表现以及使用场景方面存在显著...
### HashMap介绍和使用详解 #### 一、HashMap的数据结构 HashMap是Java集合框架的一个重要组成部分,它实现了Map接口,能够存储键值对映射。在Java编程语言中,最基本的数据结构有两种:数组和引用(模拟指针)。...
在这个主题中,我们将深入探讨如何使用JNI处理HashMap、String等对象。 首先,让我们来理解JNI的基本结构。JNI接口提供了大量的函数,让本地方法(C/C++代码)能够创建、访问和修改Java对象。要使用JNI,你需要定义...
### 使用HashMap模拟网上购物车 #### 一、项目背景与目标 在本实验中,我们通过使用Java语言中的`HashMap`来模拟一个简单的网上购物车系统。该项目的主要目的是熟悉Java集合框架中的`HashMap`类,并了解如何利用它...
HashMap是Java编程语言中一个非常重要的数据结构,它属于集合框架的一部分,主要用于存储键值对(Key-Value)数据。HashMap在内部实现上基于哈希表,也称为散列表,它提供了一种快速查找、插入和删除数据的方法,...
### ibatis 使用 HashMap 解决 resultClass 映射 在日常的软件开发过程中,尤其是在处理数据库查询时,我们经常面临一个问题:如何优雅地处理那些未知或动态变化的列名及列数的情况?在这种情况下,传统的实体类...
在IT行业中,哈希表(HashMap)是一种高效的数据结构,它使用哈希函数将键(Key)映射到数组的特定位置,以便快速存取数据。Delphi是一种强大的Object Pascal编程语言,它提供了多种实现哈希表的方式。在这个特定的...
Java HashMap 类详解 本资源详细介绍了 Java 中的 HashMap 类,包括其实现机制、Hash 存储机制、集合存储机制等方面的知识点。 1. HashMap 和 HashSet 的关系 HashMap 和 HashSet 是 Java Collection Framework ...
Java中的HashMap是一个非常重要的数据结构,它实现了Map接口,提供了键值对的高效存储和访问。HashMap基于哈希表(也称为散列表)原理工作,它允许用户通过键(Key)快速查找对应的值(Value)。在HashMap中,键和值...
哈希映射(HashMap)是Java编程语言中广泛使用的数据结构之一,主要提供键值对的存储和查找功能。HashMap的实现基于哈希表的概念,它通过计算对象的哈希码来快速定位数据,从而实现了O(1)的平均时间复杂度。在深入...
HashMap类在Java编程语言中是集合框架的一部分,它是一个基于哈希表的Map接口实现。HashMap提供了快速的插入、删除和查找操作,平均时间复杂度为O(1)。在这个压缩包“HashMap类.rar”中,包含的是易语言版本的...
### Java中HashMap, LinkedHashMap, TreeMap,HashTable的区别 在Java编程语言中,`Map`接口是集合框架中的一个重要组成部分,用于存储键值对。本文将详细分析四种常用的`Map`实现类:`HashMap`, `LinkedHashMap`, ...
HashMap是Java编程语言中常用的集合类之一,它属于哈希表数据结构,提供key-value的存储方式,并且具有快速查询的特性。然而,HashMap本身并不保证元素的顺序,特别是当涉及到遍历或输出HashMap的内容时,顺序可能会...
哈希映射(HashMap)是Java编程语言中一个非常重要的数据结构,它在《简单的key value hashmap》中被提及,通常用于存储键值对(key-value pairs)。HashMap是Java集合框架的一部分,它提供了高效的查找、插入和删除...
《马士兵老师HashMap学习笔记详解》 HashMap是Java编程语言中常用的一种数据结构,它提供了键值对(key-value pair)的存储功能,是基于哈希表实现的。马士兵老师的HashMap学习笔记深入剖析了这一核心组件的工作...