码迷,mamicode.com
首页 > 其他好文 > 详细

深入理解HashMap

时间:2018-03-07 18:56:10      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:contain   transient   amp   map   概念   fas   seed   todo   adf   

1、HashMap 是什么
   HashMap是散列表,K-V键值对集合。
 
2、HashMap 数据结构
1) 容量,增长因子,增长阔值, hashSeed 哈希因子,在
    private int threshold; // =容量 * loadFactor 增长因子 默认= 16 * 0.75 = 12 ,容量的增长,主要原因是尽量避免Hash冲突,就是为了将 Map.Entry线性分布在 Map.Entry[] talbe中,也就是尽量做到 table数组中的元素的 next 为 null;
    private loat loadFactor;//增长因子,默认为0.75 ,
    transient int hashSeed = 0;  // initHashSeedAsNeeded  初始化,并用于 final int hash(Object k) 方法中,算key的哈希值
   
2)private transient Map.Entry[]  table;  也就是HashMap,内部维护着一个 元素类型为Map.Entry的数组。但这个数组是非连续存放的比如,第1个位置,第4个位置有值,
                                                  第2个位置,第三个位置为 null。
 
3)Map.Entry<K,V> 结构详解
      private int hash;
      private K key;
      private V value;
      prinvate Map.Entry<K,V> next;    // 这里是关键中的关键
 

HashMap 存放图解

技术分享图片

 

3、核心方法跟踪详解
 
---------------------------- put(K key, V value) 源码分析 -------------------------------------------------------
 
 
1、HashMap 是什么
   HashMap是散列表,K-V键值对集合。

2、HashMap 数据结构
1) 容量,增长因子,增长阔值, hashSeed 哈希因子,在
    private int threshold; // =容量 * loadFactor 增长因子 默认= 16 * 0.75 = 12 ,容量的增长,主要原因是尽量避免Hash冲突,就是为了将 Map.Entry线性分布在 Map.Entry[] talbe中,也就是尽量做到 table数组中的元素的 next 为 null;
    private loat loadFactor;//增长因子,默认为0.75 ,
    transient int hashSeed = 0;  // 在initHashSeedAsNeeded  初始化,并用于 final int hash(Object k) 方法中,算key的哈希值
   
2)private transient Map.Entry[]  table;  也就是HashMap,内部维护着一个 元素类型为Map.Entry的数组。但这个数组是非连续存放的比如,第1个位置,第4个位置有值,
                                                  第2个位置,第三个位置为 null3)Map.Entry<K,V> 结构详解
      private int hash;
      private K key;
      private V value;
      prinvate Map.Entry<K,V> next;    // 这里是关键中的关键

HashMap 存放图解


3、核心方法跟踪详解

---------------------------- put(K key, V value) 源码分析 -------------------------------------------------------

 

 

    private Set<Map.Entry<K,V>> entrySet0() {    
           Set<Map.Entry<K,V>> es = entrySet;    
           return es != null ? es : (entrySet = new EntrySet());    
    }    
        
    //所以代码的关键点在与   new EntrySet();//什么是EntrySet,原来是HashMap中的一静态的内部类,该类继承AbstractSet类,本身就是一个集合。    
    private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {    
            public Iterator<Map.Entry<K,V>> iterator() {    
                return newEntryIterator();    
            }    
            public boolean contains(Object o) {    
                if (!(o instanceof Map.Entry))    
                    return false;    
                Map.Entry<K,V> e = (Map.Entry<K,V>) o;    
                Entry<K,V> candidate = getEntry(e.getKey());    
                return candidate != null && candidate.equals(e);    
            }    
            public boolean remove(Object o) {    
                return removeMapping(o) != null;    
            }    
            public int size() {    
                return size;    
            }    
            public void clear() {    
                HashMap.this.clear();    
            }    
        }    
        
    private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {    
            public Map.Entry<K,V> next() {    
                return nextEntry();    
            }    
        }    
        
    // 重点关注一下 HashIterator 迭代器    
    private abstract class HashIterator<E> implements Iterator<E> {    
            Entry<K,V> next;        // next entry to return     //下一个元素,因为我们知道,HashMap内部的  Map.Entry<K,V>[] table内的元素是非连续的。所以访问下一元                                                                                     // 素,不能简单的用   table[++index] 这个概念。    
            int expectedModCount;   // For fast-fail 遍历时,HashMap结构变化的次数,如果在遍历期间 modCount发生变化,则直接报错,并结束遍历    
            int index;                          // current slot              当前位置    
            Entry<K,V> current;       // current entry   当前元素    
        
            HashIterator() {    
                expectedModCount = modCount;                                //设置开始遍历时,记录HashMap结构调整的次数    
                if (size > 0) { // advance to first entry                           // 在构造方法时,先在table数组中找到第一不为空的元素,存入next属性中。    
                    Entry[] t = table;    
                    while (index < t.length && (next = t[index++]) == null)    
                        ;    
                }    
            }    
        
            public final boolean hasNext() {   //判断是否有下一个可迭代元素,只需要判断 next是否为空即可。    
                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();    
                                                                                                         // nextEntry,主要实现思路是:将next的值,赋值给当前元素,然后尝试获取下一个非空Map.Entry元                                                                                                        // 素,找到后,赋值给next元素    
                if ((next = e.next) == null) {                                            // 这句很关键,作用,先将 要本次返回的元素 next返回【开始遍历链表了】,如果该元素的next为空,                                                                                                     //说明该元素下面没有链表,说明该hash没有冲突,然后再遍历table数组,找到下一个非空元素。    
                    Entry[] t = table;    
                    while (index < t.length && (next = t[index++]) == null)    
                        ;    
                }    
                current = e;    
                return e;    
            }    
public void remove() {                                                         // 将迭代器 中current所存储的元素,对应的key,删除,然后将current域设置为空,并重新设置    
                                                                                                    //  expectedModCount的值等于modCount,,而current的赋值操作,发送在 next方法中,故    
                                                                                                    //  故,如过在遍历过程中,想删除当前元素,it.remove()方法要在it.next()方法之后调用。    
            if (current == null)    
                throw new IllegalStateException();    
            if (modCount != expectedModCount)    
                throw new ConcurrentModificationException();    
            Object k = current.key;    
            current = null;    
            HashMap.this.removeEntryForKey(k);    
            expectedModCount = modCount;    
        }    
    }    
    
//验收 再遍历 HashMap时,remove方法与next方法的使用    
public static void main(String[] args) {    
        // TODO Auto-generated method stub    
    
        HashMap<String, String> a = new HashMap();    
        a.put("a", "a");    
        a.put("b", "b");    
        a.put("c", "c");    
        a.put("d", "d");    
        a.put("e", "e");    
        a.put("f", "f");    
    
        int i = 0;    
        for (Iterator<Map.Entry<String, String>> it = a.entrySet().iterator(); it.hasNext();) {    
    
            if(i == 2) {  // 如果 修改为 i == 0,,则会抛出异常 IllegalStateException 异常。    
                it.remove();    
    
            }    
            Map.Entry<String, String> entry = it.next();    
            System.out.println(entry.getKey() + ":" + entry.getValue());    
            i ++;    
        }    
    
        System.out.println(a);    
    
    }    
-----------------------------3.2 HashMap 的遍历    public Set<Map.Entry>  entrySet(); end-----------------------    

 

深入理解HashMap

标签:contain   transient   amp   map   概念   fas   seed   todo   adf   

原文地址:https://www.cnblogs.com/zhimingxin/p/8523779.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!