对HashMap迭代的理解
来源:互联网 发布:mysql如何创建存储过程 编辑:程序博客网 时间:2024/05/17 01:30
对程序中有如下代码
指定HashMap的键值对key是字符串,value是整数类型
HashMap<String ,Integer> maps=new HashMap<String,Integer>(); maps.put("name",520); maps.put("age",24); maps.put("nima",55); Set<Map.Entry<String,Integer>> entrySet=maps.entrySet();
//用增强for循环方式迭代取出键值对的具体值 for(Map.Entry<String,Integer> entry:entrySet){ System.out.println(entry.getKey()+":"+entry.getValue()); }
输出的结果如下
age:24name:520nima:55
通过对JDK文档的了解HashMap实现了Map的接口
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
Map集合有一个方法,返回值是Set<Map.Entry<K, V>>
Set<Map.Entry<K, V>> entrySet();HashMap实现了这个方法,返回值是Set<Map.Entry<K, V>>
public Set<Map.Entry<K,V>> entrySet() {return entrySet0(); } private Set<Map.Entry<K,V>> entrySet0() { Set<Map.Entry<K,V>> es = entrySet; return es != null ? es : (entrySet = new EntrySet()); }
Map.Entry<K,V>是一个接口,里面有方法
接下来说明一下对HashMap 的理解
要理解HashMap是什么,首先要明白它的数据结构,在java编程中,最基本的结构就是两种,一个是数组,另一个是模拟指针(也就是引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap一样。HashMap是一个数组和链表的结合体,这在数据结构中一般称为链表散列,如下图所示
从图中可以分析道HashMap就是一个数组结构,当新建一个HashMap的时候,就会初始化一个数组,接下来看看java代码
static class Entry<K,V> inplements Map.Entry<K,V>{
final K key;
V value;
final int hash;
Entry<K,V> next;
......................................
}
上面的entry就是数组中的元素,它持有一个指向下一个元素的引用,就构成了链表。
当我们往HashMap中put元素的时候,先根据key和value的值得到这个元素在数组中的位置(下标),然后就额可以把这个元素放在对用的位置。如果这个元素所在的位置已经存放其它元素了,那么在通一个位置上的元素将以链表的形式存放,新加入的放在链头。从HashMap中get元素的时候,首先计算key的hashcode。找到数组中对应的位置的某一个元素,然后通过key的equals方法在对应的位置链表找到需要的元素,在这里可以做一个假设,如果每个位置上的链表只有一个元素,那么HashMap的get效率是最高的。
Hash算法
我们可以看到在HashMap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置,如何计算这个位置就是hash算法。前面说过HashMap的数据结构式数组和链表的结合,所以我们也非常希望这个HashMap里面的元素分布是均匀的,尽量是的每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的,而不用再去遍历链表的全部元素。
所以我们一开始就可能想到吧HashMap对数组的长度进行取模运算,这样一来元素的分布相对来说是比较均匀的。但是“模”运算的消耗还是比较大的。那么有什么方法是更加好的呢?
static int indexFor(int h,int length){
return h&(length-1);
}
首先算得key的hashcode值。然后跟数组的长度-1做一次与运算。看上去还是很简单的。但是里面还是有玄机的。例如数组的长度是2的4次方,那么hashcode就会和2的4次方-1做与运算。那么为什么HashMap的数组初始化大小都是2的某次方大小时的效率是最高的呢。我们以2的4次方作为一个例子,来解释一个为什么数组大小为2的幂时HashMap访问的性能最高的。
看如下图所示,左边两组是数组长度为16也就是2的4次方,右边两组是数组长度为15.两组的hashcode均为8和9,但是很明显,当他们和1110与的时候,产生相同的结果,也就是说他们会定位到数组中的同一个位置上,这就产生了碰撞,8和9被放在同一个链表上,那么查询的时候就需要遍历这个链表得到8或者9,这样就降低了查询效率。同事我们也可以发现,当数组长度为15的时候hashcode的值会与14(1110)进行与操作,那么最后一位永远是0,二0001,0011,0101,1001,1011,0111,1101这几个位置永远都不会存放元素了,空间浪费相当大,更糟糕的是在这种情况下,数组可以使用的位置比数组长度小很多,这样就说明了进一步增加了碰撞的几率,减慢了查询的效率
所以说当数组长度为2的N次幂的时候,不同的key算的得到index相同的几率比较小,那么数据在数组上分布就比较均匀,也就是说碰撞的几率就比较小,相对而言,查询的时候就不用遍历某个位置上的链表,这样查询效率就会高很多。
那么HashMap中默认的数组大小是多少呢,根据查询可以得知是16,为什么是16呢?而不是15或者20呢,那就是上面的说明可以解释了吧。显然是因为16是2的整数次幂的原因。在小数据量的时候16比起15或者20更能减少key之间的碰撞,从而加快查询效率。
- 对HashMap迭代的理解
- HashMap的迭代
- java以及jstl表达式中对HashMap的迭代
- java以及jstl表达式中对HashMap的迭代
- HashMap的迭代循环
- 说说对HashMap的理解
- 看看你对敏捷迭代方法的理解:敏捷迭代考试试题附带答案
- HashMap迭代的几种方式
- 迭代HashMap里的所有元素
- HashMap的迭代器用法
- 对HashMap的理解以及遍历方法
- 对hashMap和hashtable的理解
- 对HashMap实现原理的理解
- 循环迭代hashmap
- 对jvm堆中年轻代,老年代,永久代的理解
- “埃及分数”问题浅谈对迭代加深搜索的理解
- 【学习总结】对javascript中数组迭代方法的理解。
- 对JVM中垃圾回收机制的个人理解--新生代,老年代,永久代
- 数据结构学习之顺序表
- Oracle 树操作(select…start with…connect by…prior)
- poj 2503 Babelfish(trie树)
- JIN学习一、Android使用已有C/C++代码、第三方SO库的方法
- FPGA学习笔记(转)
- 对HashMap迭代的理解
- Spring源码由浅入深系列一 简介
- 双向、循环链表
- leetcode--single number.
- NGUI v3.6.8 (Jul 13, 2014)与旧版相比的变化
- zoj 2876 Phone List(tire 树)
- TCP/IP报文格式
- 第四十天 一乐在其中—Android的小游戏打飞机(四)添加敌机
- hadoop2.4.1 spark1.0.1编译