• HashMap源码分析


    HashMap简介:
      HashMap实现了Map接口,同时是基于哈希表的,允许存放null键和null值。HashMap和Hashtable相差无几,唯一的几点区别就是:HashMap是非线程安全的,而Hashtable是线程安全的(方法都用synchronized关键字进行修饰)。Hashtable不允许存放null键和null值。HashMap不能保证元素的存放顺序,是无序的。
    当多个线程并发地访问HashMap时,就算只有一个线程修改了其结构(增加或删除键值对才算,改变键对应的值不算),必须对HashMap进行同步处理,否则会引发线程安全问题。
      如果没有同步对象,最好在开始之前使用Collections.synchronizedMap方法进行同步处理,防止非线程安全情况发生,示例如下:
    Map m = Collections.synchronizedMap(new HashMap(…));
      当多个线程同时访问迭代器iterator时,若一个正在修改iterator,一个正在使用iteartor,将抛出ConcurrentModificationException。

    HashMap定义:
    public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {

    HashMap底层结构示意图(数组+链表结构,针对jdk1.7)


    重要属性:
    默认加载因子:
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    默认初始容量(必须是2的n次方,后面会解释):

    static final int DEFAULT_INITIAL_CAPACITY = 16;

    最大容量:

    static final int MAXIMUM_CAPACITY = 1 << 30;

    阈值(计算公式:threshold = capacity * load factor):

    int threshold;

    重要方法:(针对jdk1.7)

    带参的构造函数:

    public HashMap(int initialCapacity, float loadFactor) {
            if (initialCapacity < 0)//初始容量若小于0,则抛出非法的初始容量异常
                throw new IllegalArgumentException("Illegal initial capacity: " +
                                                   initialCapacity);
            if (initialCapacity > MAXIMUM_CAPACITY)//若初始容量超过最大容量,默认赋值最大容量
                initialCapacity = MAXIMUM_CAPACITY;
            if (loadFactor <= 0 || Float.isNaN(loadFactor))//加载因子若不大于0或者非浮点数,则抛出非法加载因子异常
                throw new IllegalArgumentException("Illegal load factor: " +
                                                   loadFactor);
    
            // Find a power of 2 >= initialCapacity
            int capacity = 1;
            while (capacity < initialCapacity)
                capacity <<= 1;
    
            this.loadFactor = loadFactor;
            threshold = (int)(capacity * loadFactor);//阈值计算
            table = new Entry[capacity];
            init();
        }

    计算哈希值所在的数组索引:

    该方法是为了计算哈希值对应的数组索引位置,本来是可以用h%length来实现的,但是&的效率要比%稍高一些,所以采用&来实现。

    而只有length是2的n次方时,才满足h%length = h&(length-1),所以HahsMap的长度都是2的n次方倍,这个也解决了上面提到的容量为什么必须得2的n次方问题。

    static int indexFor(int h, int length) {
            return h & (length-1);
        }

     get方法(返回key对应的value):

    public V get(Object key) {
            if (key == null)//key为null处理
                return getForNullKey();
         //先计算key对应的哈希值,然后再对该值进行哈希操作,得到的结果用于查找key对应的table数组位置
    int hash = hash(key.hashCode()); for (Entry<K,V> e = table[indexFor(hash, table.length)];//遍历key对应的table数组索引处的Entry链表 e != null; e = e.next) { Object k;
           //若key和某个Entry的key相同,则返回该Entry的value值
    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null;//无对应值,返回null }

     put方法(添加键值对):

    public V put(K key, V value) {
            if (key == null)//key是null处理
                return putForNullKey(value);
            int hash = hash(key.hashCode());//先计算key对应的哈希值,然后再对该值进行哈希操作,
            int i = indexFor(hash, table.length);//得到的结果用于计算对应键值对存放的位置
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {//遍历table数组该索引处的Entry链表
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//若存在key相同的,则用新值替换旧值
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }
    
            modCount++;//修改计算+1
            addEntry(hash, key, value, i);//添加Entry
            return null;
        }

    addEntry方法(将包含特定key、value、hash值的新Entry添加到特定的桶上):

    void addEntry(int hash, K key, V value, int bucketIndex) {
            Entry<K,V> e = table[bucketIndex];
            table[bucketIndex] = new Entry<>(hash, key, value, e);
            if (size++ >= threshold)//若键值对长度超过阈值,则将HashMap扩容2倍
                resize(2 * table.length);
        }

    程序示例:

    package com.abc;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    
    /**
     * @date: 2018/09/19
     * @author: alan
     * 
     */
    public class HashMapTest {
        public static void main(String[] args) {
            Map<Integer, String> map = new HashMap<>();//实例化HashMap
            map.put(1, "apple");//添加元素
            map.put(2, "banana");
            map.put(3, "watermelon");
            System.out.println("HashMap's size is : " + map.size());
            
            //foreach遍历map
            Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
            for (Map.Entry<Integer, String> entry : entrySet) {
                int key = entry.getKey();
                String value = entry.getValue();
                System.out.println("key is " + key + ", value is " + value);
            }
            
            System.out.println("============================");
            
            //使用迭代器Iterator遍历map
            Iterator iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Integer, String> entry = (Map.Entry)iterator.next();
                int key = entry.getKey();
                String value = entry.getValue();
                System.out.println("key is " + key + ", value is " + value);
            }
        }
    }

     控制台输出:

    HashMap's size is : 3
    key is 1, value is apple
    key is 2, value is banana
    key is 3, value is watermelon
    ============================
    key is 1, value is apple
    key is 2, value is banana
    key is 3, value is watermelon

     注:本文为原创,转载请附带链接:https://www.cnblogs.com/stm32stm32/p/9675722.html

  • 相关阅读:
    trackr: An AngularJS app with a Java 8 backend – Part III
    trackr: An AngularJS app with a Java 8 backend – Part II
    21. Wireless tools (无线工具 5个)
    20. Web proxies (网页代理 4个)
    19. Rootkit detectors (隐形工具包检测器 5个)
    18. Fuzzers (模糊测试器 4个)
    16. Antimalware (反病毒 3个)
    17. Debuggers (调试器 5个)
    15. Password auditing (密码审核 12个)
    14. Encryption tools (加密工具 8个)
  • 原文地址:https://www.cnblogs.com/stm32stm32/p/9675722.html
Copyright © 2020-2023  润新知