zoukankan      html  css  js  c++  java
  • 深入理解HashMap

    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-----------------------    
  • 相关阅读:
    二维数组的使用及其内存结构
    一维数组的练习
    数组的默认初始化
    数组
    完数
    break与continue
    乘法表及质数的输出法
    嵌套循环的使用
    Elasticsearch索引和查询性能调优
    elasticsearch数据冷热分离、数据冷备
  • 原文地址:https://www.cnblogs.com/zhimingxin/p/8523779.html
Copyright © 2011-2022 走看看