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

  • 基于jdk 8

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

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

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

知识点

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

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

      结果

      {null=null, 2=tony}

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

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

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

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

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

知识点:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@Test
public void test() {
Map<String, String> map = new HashMap();
map.put("1", "tony");
map.put("2", "tony");
Set<Map.Entry<String, String>> entries = map.entrySet();
Iterator<Map.Entry<String, String>> iterator = entries.iterator();
while (iterator.hasNext()) {
if (iterator.next().getKey().equals("1")) {
//不报错
iterator.remove();
//报错
map.put("3", "tony");
}
}
System.out.println(map.toString());
}

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. Redis数据库之数据基本管理操作

    了解并掌握各种数据类型的命令操作方式,以及各种数据类型值的操作方式.同时,熟练记忆列表.哈希.集合和有序集合等数据类型的常用操作命令.能根据指令格式完成相应的指令操作. ①string数据类型的练习 ...

  2. 基于Docker搭建大数据集群(三)Hadoop部署

    主要内容 Hadoop安装 前提 zookeeper正常使用 JAVA_HOME环境变量 安装包 微云下载 | tar包目录下 Hadoop 2.7.7 角色划分 角色分配 NN DN SNN clu ...

  3. 升级@Scheduled-分布式定时任务

    最近我在对项目的定时任务服务升级,希望改造成分布式,原本是利用@Scheduled注解实现,然而它并不支持分布式,如果改成quartz或者Spring Cloud Task,感觉对于自己这个简单的项目 ...

  4. linux 设置查看文本行数

    在一般模式下,即摁下esc按键下的模式: 设置行数为:set nu(此处的冒号需要带上) 取消行号为:set nonu(此处的冒号需要带上)

  5. Linux 删除命令rm

    Linux rm命令用于删除一个文件或者目录. 语法:rm [options] name... 参数: 1.-i 删除前逐一询问确认. 2.-f 即使原档案属性设为唯读,亦直接删除,无需逐一确认. 3 ...

  6. jedis指定数据库

    正常情况下,我们通过get或者set方法是从db0中取数据. 1.redis提供了 select命令,可以通过select index 这个指令,将数据库切换到index所在的那个数据库上 2.jed ...

  7. ELK系列(一):安装(elasticsearch + logstash + kibana)

    因为公司使用ELK的缘故,这两天尝试在阿里云上安装了下ELK,这里做个笔记,有兴趣的同学可以看下. 先大致介绍下ELK,ELK是三个组件的缩写,分别是elasticsearch.logstash.ki ...

  8. C语言复习————基本数据类型、运算符和表达式

    数据类型/运算符/表达式 主要分两部分介绍,第一部分介绍常用的数据类型,例如:常量和变量/整型/实型/字符型:第二部分介绍算数运算符和算数表达式以及赋值运算符和逗号运算符. 一. 常用的数据类型 1. ...

  9. ELK 学习笔记之 elasticsearch环境搭建

    ELK概述: ElasticSearch是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等 Logstash是一 ...

  10. ubuntu14.04 安装tensorflow始末

    基于ubuntu14.04 干净的系统一步步遇到的坑记录下来: 怀着平静学习的心情,问题总的能解决的! 1. 首先看了下当前python版本 python --version Python 2.7.6 ...