了解到Java8以后HashMap的实现换了,也看了很多博客一直在向我这个小菜鸡说HashMap的重要。因此我决定洗心革面,好好正视HashMap

  • 基于jdk 8

先从类注释开始入手学习,顺便提高提高英文水平。如果有任何错误欢迎指出,thanks

  1. * Hash table based implementation of the <tt>Map</tt> interface. This
  2. * implementation provides all of the optional map operations, and permits
  3. * <tt>null</tt> values and the <tt>null</tt> key. (The <tt>HashMap</tt>
  4. * class is roughly equivalent to <tt>Hashtable</tt>, except that it is
  5. * unsynchronized and permits nulls.) This class makes no guarantees as to
  6. * the order of the map; in particular, it does not guarantee that the order
  7. * will remain constant over time.

这段注释说,Hashmap基于hash表实现了map接口,并且提供了Map中的所有方法。key,value 允许为null.Hashmap可以粗略的等同与HashTable,但是不同的是HashMap是线程不安全的,并且允许为null.Hashmap并不保证map的顺序.

知识点

  • HashMap的<key,value>都允许为null

    • 额,这一点,思考了一下还是觉得写段代码验证验证,毕竟代码不会骗我
      1. @Test
      2. public void TestnullValue() {
      3. Map<String, String> map = new HashMap();
      4. map.put(null,null);
      5. map.put("2", "tony");
      6. System.out.println(map.toString());
      7. }

      结果

      1. {null=null, 2=tony}

      好吧,看来编写HashMap的前辈,木有骗我

  • HashMap线程不安全
  • HashMap无序
  1. * <p>This implementation provides constant-time performance for the basic
  2. * operations (<tt>get</tt> and <tt>put</tt>), assuming the hash function
  3. * disperses the elements properly among the buckets. Iteration over
  4. * collection views requires time proportional to the "capacity" of the
  5. * <tt>HashMap</tt> instance (the number of buckets) plus its size (the number
  6. * of key-value mappings). Thus, it's very important not to set the initial
  7. * capacity too high (or the load factor too low) if iteration performance is
  8. * important.

emem...说实话读到这一段的时候,我有点难受...要不是我天生聪慧(英文太烂),我可能会被拍死在注释中

如果hash函数把元素正确的放在容器中,HashMap提供了耗费常量时间的操作, put 和get。迭代整个集合试图耗费的时间与容器的大小有关。因此不要为HashMap设置一个太高的初始值(或者太低的负荷系数)

负荷系数是扩容的时候需要用到的

知识点:

  • 理想情况下HashMap的get, put的时间复杂度是O(1)

什么情况下不是O(1)呢?当发生Hash冲突的时候,时间复杂度就不是O(1)了

  1. * <p>An instance of <tt>HashMap</tt> has two parameters that affect its
  2. * performance: <i>initial capacity</i> and <i>load factor</i>. The
  3. * <i>capacity</i> is the number of buckets in the hash table, and the initial
  4. * capacity is simply the capacity at the time the hash table is created. The
  5. * <i>load factor</i> is a measure of how full the hash table is allowed to
  6. * get before its capacity is automatically increased. When the number of
  7. * entries in the hash table exceeds the product of the load factor and the
  8. * current capacity, the hash table is <i>rehashed</i> (that is, internal data
  9. * structures are rebuilt) so that the hash table has approximately twice the
  10. * number of buckets.

影响HashMap性能的因素有两个,容量和负荷因子。

初始容量是创建hash表的时候就确定的,负荷因子用来判断是否允许自动扩容。当hash表中的数量超过容器的大小*负荷因子的时候.Hash表要再做一次内部构建,扩容为原来的两倍.

  1. * <p>As a general rule, the default load factor (.75) offers a good
  2. * tradeoff between time and space costs. Higher values decrease the
  3. * space overhead but increase the lookup cost (reflected in most of
  4. * the operations of the <tt>HashMap</tt> class, including
  5. * <tt>get</tt> and <tt>put</tt>). The expected number of entries in
  6. * the map and its load factor should be taken into account when
  7. * setting its initial capacity, so as to minimize the number of
  8. * rehash operations. If the initial capacity is greater than the
  9. * maximum number of entries divided by the load factor, no rehash
  10. * operations will ever occur.

一般负荷因子的数值是0.75 它平衡了时间和空间复杂度。 负载因子值越大空间开销越大,但是查找的开销就越低。HashMap的绝大部分操作都是Get Put,

当哈希表中entry的总数少于负载因子和初始容量乘积时, 就不会发生rehash(内部重新构建)动作

  1. * <p>If many mappings are to be stored in a <tt>HashMap</tt>
  2. * instance, creating it with a sufficiently large capacity will allow
  3. * the mappings to be stored more efficiently than letting it perform
  4. * automatic rehashing as needed to grow the table. Note that using
  5. * many keys with the same {@code hashCode()} is a sure way to slow
  6. * down performance of any hash table. To ameliorate impact, when keys
  7. * are {@link Comparable}, this class may use comparison order among
  8. * keys to help break ties.
  9. *

如果有大量的数值需要被存储到HashMap中,那么要确保初始够大,防止map rehash自动扩容增大开销。

使用大量keys转换后的hash地址相同会降低hash表的效率,因此当keys支持java.lang.Comparable的时候,可以利用排序降低影响。

  1. * <p><strong>Note that this implementation is not synchronized.</strong>
  2. * If multiple threads access a hash map concurrently, and at least one of
  3. * the threads modifies the map structurally, it <i>must</i> be
  4. * synchronized externally. (A structural modification is any operation
  5. * that adds or deletes one or more mappings; merely changing the value
  6. * associated with a key that an instance already contains is not a
  7. * structural modification.) This is typically accomplished by
  8. * synchronizing on some object that naturally encapsulates the map.

HashMap是线程不安全的,如果多个线程同时访问hash map,至少有一个线程修改了表结构,那么必须加锁。

(改变表结构指的是,添加或删除一个或多个映射,如果是改变values值不是修改表结构)

当多个线程操作hashmap的时候,一般使用同步对象锁锁住map上

  1. * If no such object exists, the map should be "wrapped" using the
  2. * {@link Collections#synchronizedMap Collections.synchronizedMap}
  3. * method. This is best done at creation time, to prevent accidental
  4. * unsynchronized access to the map:<pre>
  5. * Map m = Collections.synchronizedMap(new HashMap(...));</pre>

如果不存在这样的对象时,应该调用Collections.synchronizedMap把HashMap转化成线程安全的SynchronizedMap

  1. public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
  2. return new SynchronizedMap<>(m);
  3. }

  1. *
  2. * <p>The iterators returned by all of this class's "collection view methods"
  3. * are <i>fail-fast</i>: if the map is structurally modified at any time after
  4. * the iterator is created, in any way except through the iterator's own
  5. * <tt>remove</tt> method, the iterator will throw a
  6. * {@link ConcurrentModificationException}. Thus, in the face of concurrent
  7. * modification, the iterator fails quickly and cleanly, rather than risking
  8. * arbitrary, non-deterministic behavior at an undetermined time in the
  9. * future.

iterators会返回所的集合视图方法。如果iterator迭代器被创建了以后,map修改了表结构(除了iterator自身的remove),iterator会抛出ConcurrentModificationException异常。因此在并发修改的时候修改表结构操作会失败

  1. @Test
  2. public void test() {
  3. Map<String, String> map = new HashMap();
  4. map.put("1", "tony");
  5. map.put("2", "tony");
  6. Set<Map.Entry<String, String>> entries = map.entrySet();
  7. Iterator<Map.Entry<String, String>> iterator = entries.iterator();
  8. while (iterator.hasNext()) {
  9. if (iterator.next().getKey().equals("1")) {
  10. //不报错
  11. iterator.remove();
  12. //报错
  13. map.put("3", "tony");
  14. }
  15. }
  16. System.out.println(map.toString());
  17. }

HashMap - 类注释的更多相关文章

  1. Hashtable和HashMap类的区别

    Hashtable和HashMap类有三个重要的不同之处.第一个不同主要是历史原因.Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现. ...

  2. VAssistX的VA Snippet Editor的类注释和函数注释

    title:类注释shortcut:=== /******************************************************** [DateTime]:$YEAR$.$M ...

  3. Java API —— HashMap类 & LinkedHashMap类

    1.HashMap类 1)HashMap类概述         键是哈希表结构,可以保证键的唯一性 2)HashMap案例         HashMap<String,String>   ...

  4. JAVA中的数据结构——集合类(线性表:Vector、Stack、LinkedList、set接口;键值对:Hashtable、Map接口<HashMap类、TreeMap类>)

    Java的集合可以分为两种,第一种是以数组为代表的线性表,基类是Collection:第二种是以Hashtable为代表的键值对. ... 线性表,基类是Collection: 数组类: person ...

  5. Hashtable和HashMap类

    Hashtable和HashMap类有三个重要的不同之处. 第一个不同主要是历史原因.Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现 ...

  6. JDK1.8源码(七)——java.util.HashMap 类

    本篇博客我们来介绍在 JDK1.8 中 HashMap 的源码实现,这也是最常用的一个集合.但是在介绍 HashMap 之前,我们先介绍什么是 Hash表. 1.哈希表 Hash表也称为散列表,也有直 ...

  7. IDEA(添加类注释以及方法注释)

    添加类注释: File---Setting----Editor----Code Style-----File and    Code  Templates--------Class #if (${PA ...

  8. PhpStorm 头部注释、类注释和函数注释的设置

    *设置位置:"Settings"->"file templates"; 如下图,设置头部注释.类注释以及函数注释,时间.用户名.文件名称等随机改变的属性, ...

  9. 超详细设置Idea类注释模板和方法注释模板

    网上找了一下,没有很详细且正确介绍Idea配置注释模板的,于是结合多篇文章自己琢磨整理出如下. 设置类注释模板 1.选择File–>Settings–>Editor–>File an ...

随机推荐

  1. 抓住那只牛!Catch That Cow POJ-3278 BFS

    题目链接:Catch That Cow 题目大意 FJ丢了一头牛,FJ在数轴上位置为n的点,牛在数轴上位置为k的点.FJ一分钟能进行以下三种操作:前进一个单位,后退一个单位,或者传送到坐标为当前位置两 ...

  2. wait()与notify()

    一,前言 ​ ​ 简单画了一下线程的流程图,只是一个大概.如图所示,线程有多种状态,那么不同状态之间是如何切换的,下面主要总结关于wait()和notify()的使用. 二,wait() ​ wait ...

  3. Ubuntu server16.04安装配置驱动418.87、cuda10.1、cudnn7.6.4.38、anaconda、pytorch超详细解决

    目录 安装GCC 安装NVIDIA驱动 1. 卸载原有驱动(没装跳过) 2. 禁用nouveau 3. 安装NVIDIA显卡驱动 安装CUDA10.1 安装cudnn 安装anaconda 安装ten ...

  4. centos 升级

    yum -y update升级所有包同时也升级软件和系统内核 yum -y upgrade只升级所有包,不升级软件和系统内核

  5. 12.Django基础十之Form和ModelForm组件

    一 Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户 ...

  6. 【SQL server初级】数据库性能优化二:数据库表优化

    数据库优化包含以下三部分,数据库自身的优化,数据库表优化,程序操作优化.此文为第二部分 数据库性能优化二:数据库表优化 优化①:设计规范化表,消除数据冗余 数据库范式是确保数据库结构合理,满足各种查询 ...

  7. 数据库系统概论——SQL

    [toc] 一.SQL查询语言概览 视图 从一个或几个基本表导出的表 数据库中只存放视图的定义而不存放视图对应的数据 视图是一个虚表 用户可以在视图上再定义视图 基本表 本身独立存在的表 SQL中一个 ...

  8. Flume 知识点(六)Flume 的监控

    简述 使用 Flume 实时收集日志的过程中,尽管有事务机制保证数据不丢失,但仍然需要时刻关注 Source.Channel.Sink 之间的消息传输是否正常. 比如,SouceChannel 传输了 ...

  9. 利用shell脚本个性化运行jar任务

    利用shell脚本可以个性化运行jar任务,废话不多说,直接上代码: #!/bin/bash APP_PATH=/root/bigdata/jars/data_migration_from_sqlse ...

  10. 移动端border-radius的几个BUG

    个人博客: http://mcchen.club 一.Android 2.3 自带浏览器不支持 % 通常我们实现一个正圆只需要border-radius: 50%即可,大致代码如下 .foo { wi ...