HashMap类

  https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html

  

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

  

  子类:LinkedHashMap,PrinterStateReasons

  一、介绍

  HashMap继承了AbstractMap类,AbstractMap类实现Map接口中的一些方法,是为了最大限度地减少实现Map接口需要进行的工作量,提高代码重用。  

  Cloneable接口可以理解为一个标记接口,它并没有定义方法。当一个对象调用Object的clone方法时,如果这个对象没有实现Cloneable接口,会引发CloneNotSupportedException异常。(关于对象的拷贝,有深拷贝和浅拷贝的知识)clone方法执行的是浅拷贝,这个接口就是指示可以使用Object的clone方法。

  

  HashMap类实现了Map接口中所有的“可选操作”,允许key和value为null,非同步。

  HashTable类与HashMap几乎一致,区别在于HashTable不允许key和value为null,而且是同步的。

  HashMap无法保证其中键值对的顺序,即它无法保证键值对的顺序会一直保持不变。

  HashMap类为基本的get和put操作,提供了常数时间的性能。

  HashMap的集合视图上的迭代器所需要的时间和(HashMap实例的容量加上键值对的数量)成正比。所以,当需要考虑迭代器的性能时,不要把HashMap实例的容量(capacity属性)设置得太高,或者别把load factor设置得太低。

  如上提到的,一个HashMap实例有两个最重要的参数影响着它的性能:初始的capacity值和load factor值。

  capacity是哈希表中桶的数量,它的初始值代表着HashMap实例创建时桶的数量。

  load factor,在这个哈希表实例进行容量自动增长前,用来度量这个哈希表“满”的程度。

  当哈希表中中键值对条目的数量超过load-factor和当前capacity的乘积时,哈希表就会被重新映射(is rehashed),这意味着它内部的数据结构被重建了,结果便是“新”的哈希表拥有了两倍的桶数。(像数组的自动扩容)

  通常,HashMap的默认load-factor是0.75,这在时间代价和空间代价提供了一个很好的平衡。

  load-factor过高会减少空间开销,但会增加查找成本,这体现在类中的大部分操作中,包括get和put。

  因此,在设置初始的capacity值时,需要好好考虑HashMap中键值条目的数量以及负载因子,以尽可能减少重新散列的次数。如果初始capacity大于(最大入口数除以负载因子),哈希表就不会进行重新散列。

  

  如果你有比较多的键值对需要存进HashMap,最好在创建它时配置一个足够大的capacity,比起容量不足然后进行重散列,这样可以更有效地存储映射。

  需要注意的是,如果多个key的hashcode()值相同,会降低哈希表的性能。为了改善这种情况,若key实现了Comparable接口,HashMap可能会利用key之间的比较顺序(comparison order)来消除“并列”(break ties)。

  由于HashMap是不同步的,当多个线程并发访问一个HashMap时,若其中至少一个线程对HashMap进行了结构性的修改,那么就必须在外部进行同步(it must be synchronized externally)。这通常是通过自然封装了HashMap的对象上完成的,如果这样的对象不存在,那么这个HashMap就应该通过Collections.synchronizedMap方法装饰,并且最好在创建时就进行,以防止这个HashMap上有以外的非同步访问:

Map m = Collections.synchronizedMap(new HashMap(...));

  (所谓的结构性修改(structural modification)是增加or删除键值记录的操作,如果仅仅是改变其中某个key关联的value,不属于结构性操作。)

  HashMap类的所有集合视图的产生方法所返回的迭代器都具有“快速失效”属性:当一个实例在迭代器被创建后被进行了结构性的修改(除了通过迭代器的remove方法),迭代器会抛出一个 ConcurrentModificationException。所以,面对并发修改,迭代器会明确而快速地失效,而不是仍然承担着并不确定的行为的风险。

  需要注意的是,迭代器并不保证它的“快速失效”属性,因为在存在非同步并发修改的情形下,不可能做出任何硬性保证。

  所以,迭代器的快速失效行为应该仅用于检测错误。

  二、HashMap的嵌套类

  继承自AbstractMap的嵌套类:AbstractMap.SimpleEntry<K,V>, AbstractMap.SimpleImmutableEntry<K,V>

  继承自Map接口的嵌套类:Map.Entry<K,V>

  事实是,HashMap中有许多嵌套类:

  如图:

  Node类实现了Map.Entry<K,V>接口,源码描述为“Basic hash bin node, used for most entries”,即为存储单条键值映射记录的数据结构;

  TreeNode类是“Entry for Tree bins”,这个是在某些情况下可以用来替代Node的(when bins get too large, they are transformed into bins of TreeNodes),该类继承自LinkedHashMap.Entry<K,V>。

  KeySet、Values、EntrySet的嵌套类和返回集合视图的三个方法相关;

  本来不打算解析嵌套类的,但是它们和很多方法息息相关,所以干脆好好分析一波!

  1、HashMap的属性

 

  如图,基本可以通过名称判断相关属性的作用。

  size,表示当前map中键值映射记录的条数;

  带treeify字段的属性,好像是和Node转换成TreeNode的操作有关的;

  threshold意思是门槛、开始,用于判断map是否进行resize操作的标准。

  table,一个包含Node元素的数组,会在第一次使用时被初始化。这个数组的长度,总是整数2的幂。

  modCount,记录这个map被结构性修改的次数;

  2、 static class Node<K,V> implements Map.Entry<K,V> 

  注意到,其中key为final,但是value不为final,关注下put方法中包含相同key时的处理方法。

  这里的hash暂时没明白干嘛的;

  next是不是表明了,键值映射记录的存储方式是链表?

/**
* Basic hash bin node, used for most entries. (See below for
* TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
*/
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
} public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; } public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
} public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
} public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}

  三、构造器

  根据Java集合框架的规约,集合类都应该提供一个无参构造器和一个Collection or Map类型的单参构造器,前者用于构造空的集合,后者用于复制另一个集合。

  •   HashMap(),构造一个空的HashMap实例,默认capacity为16,默认load-factor是0.75。
  •   HashMap(Map<? extends K,? extends V> m),这里的初始capacity,满足需求即可。
  •   HashMap(int initialCapacity)
  •   HashMap(int initialCapacity, float loadFactor)

  四、方法

  1、public int size()

  返回键map中值映射记录的条数;

  2、public boolean isEmpty()

  如果map中还没有存储键值映射的记录,返回true。

public boolean isEmpty() {
return size == 0;
}

  3、static final int hash(Object key)

  待会看看它的用法。

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

  4、public V get(Object key)

  返回指定key所映射的value值;若map不包含此key的映射,返回null。

  特殊的情况是,这个key所映射的value值恰好为null,这时就需要利用containKey()来区分这两种情况了。

  

  5、public boolean containsKey(Object key)

  查询map中是否包含指定的key

  6、public V put(K key, V value)

  关联指定的key和value,即是他们称为map中的键值对,可以通过key查到这个value。

  如果key存在,对value进行替换。

  7、public void putAll(Map<? extends K,? extends V> m)

  将指定map中的所有映射复制到此map。

  如果key已存在,则其值会被新的替换。

  8、public V remove(Object key)

  9、public void clear()

  清空map

  10、public boolean containsValue(Object value)

  判断是否map中有一个或者多个key的映射值为指定的value。

  11、public Set<K> keySet()

  Returns a Set view of the keys contained in this map.

  12、public Collection<V> values()

  Returns a Collection view of the values contained in this map.

  13、public Set<Map.Entry<K,V>> entrySet()

  Returns a Set view of the mappings contained in this map

  14、public V putIfAbsent(K key, V value)

  If the specified key is not already associated with a value (or is mapped to null) associates it with the given value and returns null, else returns the current value.

  15、public boolean remove(Object key, Object value)

  

  16、public boolean replace(K key, V oldValue, V newValue)

  Replaces the entry for the specified key only if currently mapped to the specified value.

Java源码 HashMap<K,V>的更多相关文章

  1. java源码--HashMap扩容机制学习

    待完成 Java中hash算法细述 https://blog.csdn.net/majinggogogo/article/details/80260400 java HashMap源码分析(JDK8) ...

  2. java源码--HashMap

    一.HashMap简介 1.1.HashMap概述 HashMap是基于哈希表的Map接口实现的,它存储的是内容是键值对<key,value>映射.此类不保证映射的顺序,假定哈希函数将元素 ...

  3. Java源码-HashMap(jdk1.8)

    一.hash方法 如下是jdk1.8中的源码 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = ke ...

  4. java源码-HashMap源码分析

    这次开始分析JDK8中的HashMap源码. 首先理解HashMap中几个关键变量, TREEIFY_THRESHOLD  链表转换红黑树扩容值 table 数组+链表+红黑树  size 当前存储数 ...

  5. Java源码——HashMap的源码分析及原理学习记录

    学习HashMap时,需要带着这几个问题去,会有很大的收获: 一.什么是哈希表 二.HashMap实现原理 三.为何HashMap的数组长度一定是2的次幂? 四.重写equals方法需同时重写hash ...

  6. java源码-HashMap类设计

    map(内部interface Entry<K,V>)->abstractMap(定义视图 entrySet抽象方法)->hashMap(静态内部类Node(继承Entry&l ...

  7. Java源码 HashMap.roundUpToPowerOf2原理

    int rounded = number >= MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : (rounded = Integer.highestOneBit(nu ...

  8. Java源码解读(一)——HashMap

    HashMap作为常用的一种数据结构,阅读源码去了解其底层的实现是十分有必要的.在这里也分享自己阅读源码遇到的困难以及自己的思考. HashMap的源码介绍已经有许许多多的博客,这里只记录了一些我看源 ...

  9. Java源码系列2——HashMap

    HashMap 的源码很多也很复杂,本文只是摘取简单常用的部分代码进行分析.能力有限,欢迎指正. HASH 值的计算 前置知识--位运算 按位异或操作符^:1^1=0, 0^0=0, 1^0=0, 值 ...

随机推荐

  1. APScheduler 3.0.1浅析

    简介 APScheduler是一个小巧而强大的Python类库,通过它你可以实现类似Unix系统cronjob类似的定时任务系统.使用之余,阅读一下源码,一方面有助于更好的使用它,另一方面,个人认为a ...

  2. Android8.0新特性总结

    1.通知渠道:开发者可以自定义应用的通知内容类别,为用户提供一个可以对通知精细控制的接口,用户可以对通知    进行精细的掌控 开发指南 创建通知渠道的步骤: 创建 NotificationChann ...

  3. linux安装jdk1.8之后报错Error: dl failure on line 893的解决办法

    问题描述:安装jdk1.8之后,输入java -version查看安装是否成功之后,报错:   报错如下: Error: dl failure on line 893 Error: failed /u ...

  4. leetcode 日常清单

    a:excellent几乎一次ac或只有点小bug很快解决:半年后再重刷: b:经过艰难的debug和磕磕绊绊或者看了小提示才刷出来: c:经过艰难的debug没做出来,看答案刷的: 艾宾浩斯遗忘曲线 ...

  5. 带你体验Android自定义圆形刻度罗盘 仪表盘 实现指针动态改变

    带你体验Android自定义圆形刻度罗盘 仪表盘 实现指针动态改变 转 https://blog.csdn.net/qq_30993595/article/details/78915115   近期有 ...

  6. linux下编译安装ACE-6.4.2(adpative communication environment)

    1.环境 CentOS-6.5-x86_64-bin-DVD1.iso VMware_workstation_full_12.5.2 (2).exe ACE-6.4.2.tar.gz 下载链接:htt ...

  7. Scala面向对象01

  8. HTML基础知识自学教程

    HTML 是用来描述网页的一套标记标签,是我们在web前端开发中的基础.下面PHP程序员雷雪松主要结合自己的经验给大家分享下HTML的基础知识,以及在自学过程中一些比较常用的和重要的HTML知识点. ...

  9. 直方图均衡化与直方图规定化的MATLAB实现

    目录 1.直方图均衡化 2.直方图规定化 @ 1.直方图均衡化 对图像进行非线性拉伸,重新分配图像像元值,使一定灰度范围内像元值的数量大致相等就是直方图的均衡化.原来直方图中间的峰顶部分对比度得到增强 ...

  10. PI膜热作用机理

    一.热分析法: 二.研究成果 1.PI膜热老化机理 实验条件:8根500w的碘钨灯加热,200倍光学显微镜观察,PI膜的技术指标 实验概述:本研究分别以150 ℃ ,  175 ℃ , 200 ℃ , ...