JDK1.7 HashMap源码详解

16 篇文章 0 订阅
6 篇文章 0 订阅

文章参考:https://www.cnblogs.com/skywang12345/p/3310835.html

 1. HashMap概述

      HashMap是存储键值对内容的一个集合,继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口,HashMap的实现不是线程同步的,即非线程安全的,key和value都是支持null的。

      HashMap根据键的hashCode值获取存储位置,存储数据,大部分情况可以直接定位到它的值,访问速度快,但是其遍历的顺序确实不确定的(无序)。

 2. HashMap存储结构

    数组: 

          数组的存储区是连续的,占用内存严重,故空间复杂度很大。但数组的二分查找时间度小;

          数组的特点:寻址容易,插入和删除困难。

    链表:

          链表的储存区离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度大;

          链表的特点:寻址困难,插入和删除容易。

    哈希表

         Jdk1.7 : 数组+链表 Jdk1.8 数组+链表+红黑树 (寻址容易,插入和删除也容易)

    结构图

         

  3 HashMap成员概述

      3.1  重要的成员变量

        transient Entry[] table:是一个Entry[]数组类型,而Entry实际上是一个单向链表,哈希表中的“key-value键值对”都存储在Entry数组中,

        transient int size:是HashMap的大小,是保存HashMap中保存键值对的数量

        final float loadFactor:加载因子 

        int threshold:是HashMap的阈值,用来判断是否需要调整HashMap的容量,threshold = 容量*加载因子(最大可承受装载的容量),达到最大threshold值时,就需要扩容 

        transient volatile int modCount:fail-fast机制的需要。

        trasient

           就是让某些被修饰的成员属性变量不被序列化

        volatile

             是一个类型修饰符(type specifier)。volatile的作用是作为指令关键字, 确保本条指令不会因编译器的优化而省略, 且要求每次直接读值。 volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。

        final 

            变量不可变,被修饰后就是一个常量

         Entry[] table 源码详解

            static class Entry<K,V> implements Map.Entry<K,V> {                

                final K key;  // 成员变量

                V value; 

                Entry<K,V> next;   // 指向下一个节点 

                final int hash; 

                构造函数。 初始化操作,输入参数包括哈希值(h), 键(k), 值(v), 下一节点(n) 

                Entry(int h, K k, V v, Entry<K,V> n) { 

                    value = v; 

                    next = n; 

                    key = k; 

                    hash = h;

                } 

                public final K getKey() { 

                    return key; 

                } 

                public final V getValue() { 

                    return value;

                } 

                public final V setValue(V newValue) { 

                    V oldValue = value; 

                    value = newValue; 

                    return oldValue; 

                } 

                判断两个Entry是否相等

                先判断两个对象类型是否相等,不相同直接返回false

                相同然后判断两个Entry的key和value是否相等,相同返回true 否则false   

                public final boolean equals(Object o) { 

                    if (!(o instanceof Map.Entry))     //判断类型是否相同

                        return false;

                    Map.Entry e = (Map.Entry         //获取key和value用于判断

                    Object k1 = getKey(); 

                    Object k2 = e.getKey(); 

                    if (k1 == k2 || (k1 != null && k1.equals(k2))) { 

                        Object v1 = getValue(); 

                        Object v2 = e.getValue(); 

                    if (v1 == v2 || (v1 != null && v1.equals(v2))) 

                        return true;

                    } 

                    return false; 

                } 

                实现hashCode() 

                public final int hashCode() { 

                    return (key==null ? 0 : key.hashCode()) ^(value==null ? 0 : value.hashCode()); 

                } 

                public final String toString() { 

                    return getKey() + "=" + getValue(); 

                } 

                当向HashMap中添加元素时,绘调用recordAccess(),这里不做任何处理 

                void recordAccess(HashMap<K,V> m) { } 

                当从HashMap中删除元素时,绘调用recordRemoval(),这里不做任何处理 

                void recordRemoval(HashMap<K,V> m) { }

            }

    3.2 重要的成员方法

        Object clone()

        boolean containsKey(Object key)

        boolean containsValue(Object value)

        boolean isEmpty()

        int size()

        void clear()

        void putAll(Map<? extends K, ? extends V> map)

        V put(K key, V value)

        V get(Object key)

        V remove(Object key)

        Collection<V> values()

        Set<K> keySet()

        Set<Entry<K, V>> entrySet()

    3.3 构造函数

        HashMap()默认构造函数。

        HashMap(int capacity) 指定“容量大小”的构造函数

        HashMap(int capacity, float loadFactor) 指定“容量大小”和“加载因子”的构造函数

        HashMap(Map<? extends K, ? extends V> map) 包含“子Map”的构造函数

  4 HashMap成员源码详解  (大量代码袭来)注释符号多了,看着不舒服就去了,嘿嘿   

        package java.util;

        import java.io.*;

        public class HashMap<K,V>  extends AbstractMap<K,V>  implements Map<K,V>, Cloneable, Serializable

       {

            默认的初始容量是16,必须是2的幂。

            static final int DEFAULT_INITIAL_CAPACITY = 16;

            最大容量(必须是2的幂且小于2的30次方,传入容量过大将被这个值替换) 

            static final int MAXIMUM_CAPACITY = 1 << 30; 

            默认加载因子       

            static final float DEFAULT_LOAD_FACTOR = 0.75f;

            存储数据的Entry数组,长度是2的幂, HashMap是采用拉链法实现的,每一个Entry本质上是一个单向链表 

            transient Entry[] table;

            HashMap的大小,它是HashMap保存的键值对的数量 

            transient int size;

            HashMap的阈值,用于判断是否需要调整HashMap的容量(threshold = 容量*加载因子) 

            int threshold;

            加载因子实际大小 

            final float loadFactor;

            HashMap被改变的次数 (fail-fast机制)

            transient volatile int modCount;

           默认构造函数。     

           public HashMap() {   

                设置加载因子

                this.loadFactor = DEFAULT_LOAD_FACTOR;     

                设置HashMap阈值,当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍。 

                threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);  

                创建Entry数组,用来保存数据 

                table = new Entry[DEFAULT_INITIAL_CAPACITY];    

                init();

             }         

           指定“容量大小”的构造函数    

           public HashMap(int initialCapacity) {  

                 this(initialCapacity, DEFAULT_LOAD_FACTOR);  

            }     

            指定“容量大小”和“加载因子”的构造函数 ,先判断参数合法性后初始化

            public HashMap(int initialCapacity, float loadFactor) {

              参数不合法抛出异常 

              if (initialCapacity < 0)        

                   throw new IllegalArgumentException("Illegal initial capacity: " +initialCapacity);

               if (initialCapacity > MAXIMUM_CAPACITY) 

                   initialCapacity = MAXIMUM_CAPACITY;

              if (loadFactor <= 0 || Float.isNaN(loadFactor))   

                   throw new IllegalArgumentException("Illegal load factor: " +loadFactor); 

               计算capacity  要求大于initialCapacity的最小的2的幂(HashMap容量大小必须位2的幂) 

               int capacity = 1; 

               while (capacity < initialCapacity) 

                   capacity <<= 1; //左移运算符,相当于capacitry乘以2

              设置“加载因子” 

              this.loadFactor = loadFactor;

              设置HashMap阈值,当HashMap中存储数据的数量超过threshold时,就需要扩容

              threshold = (int)(capacity * loadFactor);

              创建Entry数组,用来存储数据

              table = new Entry[capacity];

              init(); 

        }

         包含子map的构造函数 

         public HashMap(Map<? extends K, ? extends V> m) {

             this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);

             将m中的全部元素逐个添加到HashMap中 

             putAllForCreate(m);

         } 

        将m中的全部元素都添加到HashMap中, 该方法被内部的构造HashMap的方法所调用。

        private void putAllForCreate(Map<? extends K, ? extends V> m) { 

            // 利用迭代器将元素逐个添加到HashMap中 

            for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { 

                Map.Entry<? extends K, ? extends V> e = i.next(); 

                putForCreate(e.getKey(), e.getValue()); //将单个添加的方法(下面讲述)

            } 

        } 

        参考文献:JDK 源码中 HashMap 的 hash 方法原理是什么? - 知乎

        1static int hash(int h) {

            这段代码是为了对key的hashCode进行扰动计算,防止不同hashCode的高位不同但低位相同导致的hash冲突。

            简单点说,就是为了把高位的特征和低位的特征组合起来,降低哈希冲突的概率,也就是说,尽量做到任何一位的变化都能对最终得到的结果产生影响。

             h ^= (h >>> 20) ^ (h >>> 12); 

             return h ^ (h >>> 7) ^ (h >>> 4); 

         }

        返回索引值  (下标)

        一般我们利用hash码,计算出在一个数组的索引,常用方式是”h % length”, 也就是求余的方式 ,可能是这种方式效率不高, SUN大师们发现, 当容量一定是2^n时,h & (length - 1) == h % length”. 按位运算特别快 . 

        对于length = 16, 对应二进制1 0000, length-1=0 1111

         假设此时h = 17 . 

           1.使用h % length, 也就是17 % 16, 结果是1 . 

           2.使用h & (length - 1), 也就是 1 0001 & 0 1111, 结果也是1 . 

              我们会发现, 因为0 1111低位都是1, 进行&操作, 就能成功保留1 0001对应的低位, 将高位的都丢弃, 低位是多少, 最后结果就是多少 .刚好低位的范围是0~15, 刚好是长度为length=16的所有索引 .

        static int indexFor(int h, int length) {

              return h & (length-1); 保证返回值的小于length   

         } 

        public int size() { return size;  } 

        public boolean isEmpty() {  return size == 0; }

        获取key对应的value 

         public V get (Object key) {

             判断是否为null,如果key是null,调用getForNulKey取出null的value值 

             if (key == null)   

                 return getForNullKey();

             根据key的hashCode计算hash值 

             int hash = hash(key.hashCode());

             找出hash值相应位置索引的Entry的链表,如果不为null,循环判断是否有相同的key和hash 

             for (Entry<K,V> e = table[indexFor(hash, table.length)];  e != null;  e = e.next) { 

                     Object k; 

                    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) //判断key和hash是否相同。相同就返回value 

                         return e.value; 

                 } 

             return null; 

         }

        获取key为null的元素的值 ,HashMap将“key为null”的元素存储在 table[0] 位置!   

        private V getForNullKey() {   

            for (Entry<K,V> e = table[0]; e != null; e = e.next) {   

                if (e.key == null)   

                    return e.value;   

            }   

            return null;   

        }

         HashMap是否包含key 

         public boolean containsKey (Object key) {   

             return getEntry(key) != null; 

         } 

         根据key 要求返回Entry对象

         final Entry<K,V> getEntry (Object key) {   

             获取哈希值 ,key为null的元素存储在table[0]上,key不为null,则调用hash()计算哈希值 

             int hash = (key == null) ? 0 : hash(key.hashCode());

             找出hash值相应位置索引的Entry的链表,循环判断是否有相同的key和hash  ,相同则返回

             for (Entry<K,V> e = table[indexFor(hash, table.length)];  e != null; e = e.next) { 

                 Object k; 

                 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) 

                     return e; 

             } 

               return null; 

          } 

         将key-value添加到HashMap中 

         public V put (K key, V value) {

             若key为null,则将该键值对添加到table[0]中。 

             if (key == null)

                 return putForNullKey(value);

             若key不为null,则计算该key的哈希值,然后将其添加到该哈希值对应的链表中。 

             int hash = hash(key.hashCode()); 

             int i = indexFor(hash, table.length); 

             循环Entry判断该key是否存在,存在的话,则用新的value取代旧的value。然后退出! 

             for (Entry<K,V> e = table[i]; e != null; e = e.next) { 

                 Object k; 

                 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 

                     V oldValue = e.value; 

                     e.value = value; 

                     e.recordAccess(this); 

                     return oldValue;  //存在值得时候,覆盖后返回原值

                 } 

             } 

            若“该key”对应的键值对不存在,则将“key-value”添加到table中 

             modCount++; 

             addEntry(hash, key, value, i); 

             return null; 

         }

         putForNullKey()的作用是将key为null键值对添加到table[0]位置 

         private V putForNullKey (V value) {   

             for (Entry<K,V> e = table[0]; e != null; e = e.next) { 

                 if (e.key == null) { 

                     V oldValue = e.value; 

                     e.value = value; 

                     e.recordAccess(this); 

                     return oldValue; 

                 } 

             } 

            这里的完全不会被执行到!因为本方法就是将key为null的存储到table[0]位置上   

            modCount++; 

            addEntry(0, null, value, 0); 

            return null; 

        } 

        新增Entry。将key-value插入指定位置,bucketIndex是位置索引。 

        void addEntry(int hash, K key, V value, int bucketIndex) { 

    1、判断当前个数是否大于等于阈值

       2、当前存放是否发生哈希碰撞

      如果上面两个条件否发生,那么就扩容

   if ((size >= threshold) && (null != table[bucketIndex])) {

    //扩容,并且把原来数组中的元素重新放到新数组中

    resize(2 * table.length);

    hash = (null != key) ? hash(key) : 

    bucketIndex = indexFor(hash, table.length);

   }

   createEntry(hash, key, value, bucketIndex);

     

        createEntry() 创建Entry。将key-value插入指定位置,bucketIndex是位置索引。 

        void createEntry(int hash, K key, V value, int bucketIndex) { 

            保存bucketIndex位置的值到·e中 

            Entry<K,V> e = table[bucketIndex]; 

            设置“bucketIndex”位置的元素为“新Entry”, 设置“e”为“新Entry的下一个节点”

            table[bucketIndex] = new Entry<K,V>(hash, key, value, e); 

            size++; 

            和addEntry区别于没有判断是否超过了阈值

        }   

        它和addEntry的区别是: 

            1.addEntry()

                 对于我们新建的HashMap,不断的向里面添加值的时候我们是不知道是否会超过阈值,所以需要使用addEntry(),put()是通过addEntry()新增Entry的。

                用于HashMap的实际容量可能超过阈值的情况下。 

            2.createEntry()

               我们调用HashMap带有Map参数的构造函数,需要将Map的全部元素添加到HashMap中,在添加之前,我们已经计算好HashMap的容量和阈值,确定Map中的全部元素添加到HashMap中,都不会超过HashMap的阈值。 此时,调用createEntry()即可。 

               用于HashMap的实际容量不会超过阈值的情况下。 

        创建HashMap对应的添加方法, 

           putForCreate()和put()不同的是

           putForCreate()是内部方法,它被构造函数等调用,用来创建HashMap 

           而put()是对外提供的往HashMap中添加元素的方法*/ 

        private void putForCreate(K key, V value) { 

            int hash = (key == null) ? 0 : hash(key.hashCode()); 

            int i = indexFor(hash, table.length); 

            若该HashMap表中存在“键值等于key”的元素,则替换该元素的value值 

            for (Entry<K,V> e = table[i]; e != null; e = e.next) { 

                Object k; 

                if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { 

                    e.value = value; 

                    return; 

                } 

            } 

            若该HashMap表中不存在键值等于key的元素,则将该key-value添加到HashMap中 

            createEntry(hash, key, value, i); 
       } 

        重新调整HashMap的大小,newCapacity是调整后的单位 

        void resize(int newCapacity) { 

            Entry[] oldTable = table; 

            int oldCapacity = oldTable.length; 

            判断是否已经超过最大容量(1073742824),超过了的话,就将threshold设置为Integer.MAX_VALUE(214743647)

            if (oldCapacity == MAXIMUM_CAPACITY) { 

                threshold = Integer.MAX_VALUE; 

                return; 

            } 
    
            新建一个HashMap,将旧HashMap的全部元素添加到新HashMap中,

            Entry[] newTable = new Entry[newCapacity]; 

            将数据转移到新数组中,参数,新数组和是否需要重新计算hash值

            transfer(newTable, initHashSeedAsNeeded(newCapacity) );

            table = newTable; 

            threshold = (int)(newCapacity * loadFactor); 

        }     

        扩容的时候,将HashMap中的全部元素都添加到newTable中 (转移)

        void transfer(Entry[] newTable, boolean rehash) {

            int newCapacity = newTable.length; //容量大小

            for (Entry<K,V> e : table) { //循环数组,转移赋值,

                while(null != e) {

                    Entry<K,V> next = e.next;

                    if (rehash) {   //是否需要计算hash值(一般不会重新计算)

                        e.hash = null == e.key ? 0 : hash(e.key);

                    }

                    int i = indexFor(e.hash, newCapacity);

                    e.next = newTable[i]; //将e.next指向table[i]

                    newTable[i] = e;  //将table[i] 向下移

                    e = next;

                    经过这几步,我们会发现转移的时候是逆序的。假如转移前链表顺序是1->2->3,那么转移后就会变成3->2->1,死锁问题就是因为1->2的同时2->1(两个线程下),HashMap 的死锁问题就出在这个transfer()函数上。

                }

            }

        }

       

        将m的全部元素都添加到HashMap中 

        public void putAll(Map<? extends K, ? extends V> m) { 

            个数的校验

            int numKeysToBeAdded = m.size(); 

            if (numKeysToBeAdded == 0) 

                return; 

            计算容量是否足够, 当需要的容量小于阈值时(实际容量),则将容量x2。 

            if (numKeysToBeAdded > threshold) { 

                int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); 

                判断是否已经超过最大容量(1073742824),超过了的话,就将threshold设置为Integer.MAX_VALUE(214743647)

                if (targetCapacity > MAXIMUM_CAPACITY) 

                    targetCapacity = MAXIMUM_CAPACITY; 

                如果当前容量小于目标容量,计算并保证为2的幂,然后扩容

                int newCapacity = table.length; 

                while (newCapacity < targetCapacity) 

                    newCapacity <<= 1; 

                因为如果执行了重新计算,肯定上一次大,然后进行扩容的操作

                if (newCapacity > table.length) 

                    resize(newCapacity); 

            } 

            通过迭代器,将m中的元素通过put方法逐个添加到HashMap中。 

            for (Iterator<? extends Map.Entry<? extends K, ? extends V>> i = m.entrySet().iterator(); i.hasNext(); ) { 

                Map.Entry<? extends K, ? extends V> e = i.next(); 

                put(e.getKey(), e.getValue()); 

            } 
        }     

        删除键为key的元素

        public V remove(Object key) { 

            Entry<K,V> e = removeEntryForKey(key); 

            return (e == null ? null : e.value); 

        } 


        删除键为key的元素

        final Entry<K,V> removeEntryForKey(Object key) { 

            int hash = (key == null) ? 0 : hash(key.hashCode());            // 根据key求哈希值

            int i = indexFor(hash, table.length);             // 计算数组的下标 

            Entry<K,V> prev = table[i];      //取出对应的链表

            Entry<K,V> e = prev;      //遍历使用,

            删除链表中键为key的元素 

            本质是删除单向链表中的节点 

            while (e != null) { 

                Entry<K,V> next = e.next; 

                Object k; 

                找出该节点后,然后容量减1,

                if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {

                    modCount++; 

                    size--; 

                    判断该节点是否是该链表的第一个。

                    if (prev == e) 

                        table[i] = next; 

                    else 

                        prev.next = next; 

                    e.recordRemoval(this); 

                    return e; 

                } 

                prev = e; 

                e = next; 

            } 

            return e; 
        } 

        删除键值对 o

        final Entry<K,V> removeMapping(Object o) { 

            先判断o对象的类型

            if (!(o instanceof Map.Entry)) 

                return null;

            Map.Entry<K,V> entry = (Map.Entry<K,V>) o; 

            Object key = entry.getKey(); 

            int hash = (key == null) ? 0 : hash(key.hashCode()); 

            int i = indexFor(hash, table.length); 

            Entry<K,V> prev = table[i]; 

            Entry<K,V> e = prev; 

            删除链表中的键值对e,循环桶中的元素,找到需要删除的元素,然后删除对应的节点

            while (e != null) { 

                Entry<K,V> next = e.next; 

                if (e.hash == hash && e.equals(entry)) { 

                    modCount++; 

                    size--; 

                    if (prev == e) 

                        table[i] = next; 

                    else 

                        prev.next = next; 

                    e.recordRemoval(this); 

                    return e; 

                } 

                prev = e; 

                e = next; 

           } 

           return e; 

        } 

        清空HashMap,将所有的元素设为null 

        public void clear() { 

            modCount++; 

            Entry[] tab = table; 

            for (int i = 0; i < tab.length; i++) 

                tab[i] = null; 

            size = 0; 

        } 


        是否包含值为value的元素 

        public boolean containsValue(Object value) { 

            若value为null,则调用containsNullValue()查找 

            if (value == null) 

                return containsNullValue(); 

            若value不为null则查找HashMap中是否有值为value的节点。 

            Entry[] tab = table; 

            for (int i = 0; i < tab.length ; i++) 

                for (Entry e = tab[i] ; e != null ; e = e.next) 

                    if (value.equals(e.value)) 

                        return true; 

            return false; 

        } 

        是否包含null值 

        private boolean containsNullValue() { 

            Entry[] tab = table; 

            for (int i = 0; i < tab.length ; i++) 

                for (Entry e = tab[i] ; e != null ; e = e.next) 

                    if (e.value == null) 

                    return true; 

            return false; 

        } 

        克隆HashMap,并返回Object对象 

        public Object clone() { 

            HashMap<K,V> result = null; 

            try { 

                result = (HashMap<K,V>)super.clone(); 

            } catch (CloneNotSupportedException e) { 

                // assert false;

            } 

            result.table = new Entry[table.length]; 

            result.entrySet = null; 

            result.modCount = 0; 

            result.size = 0; 

            result.init(); 

            调用putAllForCreate()将全部元素添加到HashMap中 

            result.putAllForCreate(this); 

            return result; 
        } 

        HashIterator是HashMap迭代器的抽象出来的父类,实现了公共了函数。 

        它包含key迭代器(KeyIterator)、“alue迭代器(ValueIterator)”和“Entry迭代器(EntryIterator)”3个子类。 

        private abstract class HashIterator<E> implements Iterator<E> {  

            Entry<K,V> next;  // 下一个元素

            int expectedModCount;   // expectedModCount用于实现fast-fail机制。 

            int index;    // 当前索引 

            Entry<K,V> current;  // 当前元素  

            HashIterator() {

                expectedModCount = modCount;

                if (size > 0) { 

                    Entry[] t = table; 

                    将next指向table中第一个不为null的元素。 

                    这里利用了index的初始值为0,从0开始依次向后遍历,直到找到不为null的元素就退出循环。 

                    while (index < t.length && (next = t[index++]) == null) ; 

                } 

            }

        public final boolean hasNext() { 

            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(); 

            一个Entry就是一个单向链表 ,若该Entry的下一个节点不为空,就将next指向下一个节点; 

            否则,将next指向下一个链表(也是下一个Entry)的不为null的节点。 

            if ((next = e.next) == null) { 

                Entry[] t = table; 

                while (index < t.length && (next = t[index++]) == null) ; 

            } 
            current = e; 

            return e; 

        } 


        删除当前元素 
        public void remove() { 

            if (current == null) 

                throw new IllegalStateException(); 

            if (modCount != expectedModCount) 

                throw new ConcurrentModificationException(); 

            Object k = current.key; 

            current = null; 

            HashMap.this.removeEntryForKey(k); 

            expectedModCount = modCount; 

        }          

        value的迭代器

        private final class ValueIterator extends HashIterator<V> {

            public V next() {

                return nextEntry().value;

            }

        }

        key的迭代器

        private final class KeyIterator extends HashIterator<K> {

            public K next() {

                return nextEntry().getKey();

            }

        }
        Entry的迭代器

        private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {

            public Map.Entry<K,V> next() {

                return nextEntry();

            }

        }
        返回一个“key迭代器”

        Iterator<K> newKeyIterator() {

            return new KeyIterator();

        }

        返回一个“value迭代器”

        Iterator<V> newValueIterator() {

            return new ValueIterator();

        }

        返回一个“entry迭代器

        Iterator<Map.Entry<K,V>> newEntryIterator() {

            return new EntryIterator();

        }

        返回“key的集合”,实际上返回一个“KeySet对象”     

        public Set<K> keySet() { 

            Set<K> ks = keySet; 

            return (ks != null ? ks : (keySet = new KeySet())); 
        } 

        Key对应的集合 ,KeySet继承于AbstractSet,说明该集合中没有重复的Key。

        private final class KeySet extends AbstractSet<K> { 

            public Iterator<K> iterator() { 

            return newKeyIterator(); 

        } 

        public boolean contains(Object o) { 

            return containsKey(o); 

        } 

        public boolean remove(Object o) { 

            return HashMap.this.removeEntryForKey(o) != null; 

        } 

        public void clear() { 
            HashMap.this.clear(); 
        } 

        返回“value集合”,实际上返回的是一个Values对象 

        public Collection<V> values() { 

            Collection<V> vs = values; 

            return (vs != null ? vs : (values = new Values())); 

        } 

        value集合,Values继承于AbstractCollection,不同于KeySet继承于AbstractSet, 

        Values中的元素能够重复。因为不同的key可以指向相同的value。 

        private final class Values extends AbstractCollection<V> { 

            public Iterator<V> iterator() { 

                return newValueIterator(); 

            } 

            public int size() { 

                return size; 

            } 

            public boolean contains(Object o) {

                return containsValue(o); 

            } 

            public void clear() { 

                HashMap.this.clear(); 

            } 

        } 

        返回“HashMap的Entry集合” 

        public Set<Map.Entry<K,V>> entrySet() {

            return entrySet0();

        }     

        返回“HashMap的Entry集合”,它实际是返回一个EntrySet对象 

        private Set<Map.Entry<K,V>> entrySet0() { 

            Set<Map.Entry<K,V>> es = entrySet; 

            return es != null ? es : (entrySet = new EntrySet()); 

        } 

        EntrySet对应的集合 

        EntrySet继承于AbstractSet,说明该集合中没有重复的EntrySet。 

        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(); 

            } 

        } 

        java.io.Serializable的写入函数 

        将HashMap的“总的容量,实际容量,所有的Entry”都写入到输出流中 

        private void writeObject(java.io.ObjectOutputStream s) throws IOException

        { 

            Iterator<Map.Entry<K,V>> i = (size > 0) ? entrySet0().iterator() : null; 

            s.defaultWriteObject(); 

            s.writeInt(table.length); 

            s.writeInt(size); 

            if (i != null) { 

                while (i.hasNext()) {

                    Map.Entry<K,V> e = i.next(); 

                    s.writeObject(e.getKey()); 

                    s.writeObject(e.getValue()); 

                } 

            } 

        }

        private static final long serialVersionUID = 362498820763181265L; 

        java.io.Serializable的读取函数:根据写入方式读出 

        将HashMap的“总的容量,实际容量,所有的Entry”依次读出

        private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException 

        { 

            s.defaultReadObject(); 

            int numBuckets = s.readInt(); 

            table = new Entry[numBuckets];

            init();         

            int size = s.readInt(); 

            for (int i=0; i<size; i++) { 

                K key = (K) s.readObject(); 

                V value = (V) s.readObject(); 

                putForCreate(key, value); 

            } 

        } 

        返回“HashMap总的容量” 

        int capacity() { return table.length; } 

        返回“HashMap的加载因子” 

        float loadFactor() { return loadFactor; } 

    }

       

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值