zoukankan      html  css  js  c++  java
  • HashMap源码理解与分析

    /**
      * HashMap是常用的Java集合之一,是基于哈希表的Map接口的实现。与HashTable主要区别为不支持同步和允许null作为key和value。
      * HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致。
      * 如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。
      * 在JDK1.6中,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。
      * 但是当位于一个数组中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。
      * 而JDK1.8中,HashMap采用数组+链表+红黑树实现,当链表长度超过阈值8时,将链表转换为红黑树,这样大大减少了查找时间。
      * 原本Map.Entry接口的实现类Entry改名为了Node。转化为红黑树时改用另一种实现TreeNode。
      */
     1 public class HashMap<K, V> extends AbstractMap<K, V>
     2         implements Map<K, V>, Cloneable, Serializable {
     3 
     4     private static final long serialVersionUID = 362498820763181265L;
     5 
     6 
     7     /**
     8      * 默认的初始容量(容量为HashMap中槽的数目)是16,且实际容量必须是2的整数次幂。
     9      */
    10     static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    11 
    12     /**
    13      * 最大容量(必须是2的幂且小于2的30次方,传入容量过大将被这个值替换)
    14      */
    15     static final int MAXIMUM_CAPACITY = 1 << 30;
    16 
    17     /**
    18      * 默认装填因子0.75,如果当前键值对个数 >= HashMap最大容量*装填因子,进行rehash操作
    19      */
    20     static final float DEFAULT_LOAD_FACTOR = 0.75f;
    21 /**
    22      * JDK1.8 新加,Entry链表最大长度,当桶中节点数目大于该长度时,将链表转成红黑树存储;
    23      */
    24     static final int TREEIFY_THRESHOLD = 8;
    25 
    26     /**
    27      * JDK1.8 新加,当桶中节点数小于该长度,将红黑树转为链表存储;
    28      */
    29     static final int UNTREEIFY_THRESHOLD = 6;
    30 
    31     /**
    32      * 桶可能被转化为树形结构的最小容量。当哈希表的大小超过这个阈值,才会把链式结构转化成树型结构,否则仅采取扩容来尝试减少冲突。
    33      * 应该至少4*TREEIFY_THRESHOLD来避免扩容和树形结构化之间的冲突。
    34      */
    35     static final int MIN_TREEIFY_CAPACITY = 64;
    36 
    37  /**
    38      * JDK1.6用Entry描述键值对,JDK1.8中用Node代替Entry
    39      */
    40     static class Node<K, V> implements Map.Entry<K, V> {
    41         // hash存储key的hashCode
    42         final int hash;
    43         // final:一个键值对的key不可改变
    44         final K key;
    45         V value;
    46         //指向下个节点的引用
    47         Node<K, V> next;
    48 
    49         //构造函数
    50         Node(int hash, K key, V value, Node<K, V> next) {
    51             this.hash = hash;
    52             this.key = key;
    53             this.value = value;
    54             this.next = next;
    55         }
    56 
    57         public final K getKey() {
    58             return key;
    59         }
    60 
    61         public final V getValue() {
    62             return value;
    63         }
    64 
    65         public final String toString() {
    66             return key + "=" + value;
    67         }
    68 
    69         public final int hashCode() {
    70             return Objects.hashCode(key) ^ Objects.hashCode(value);
    71         }
    72 
    73         public final V setValue(V newValue) {
    74             V oldValue = value;
    75             value = newValue;
    76             return oldValue;
    77         }
    78     public final boolean equals(Object o) {
    79             if (o == this)
    80                 return true;
    81             if (o instanceof Map.Entry) {
    82                 Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
    83                 if (Objects.equals(key, e.getKey()) &&
    84                         Objects.equals(value, e.getValue()))
    85                     return true;
    86             }
    87             return false;
    88         }
    89     }
    /**
      * HashMap中键值对的存储形式为链表节点,hashCode相同的节点(位于同一个桶)用链表组织
      * hash方法分为三步:
      * 1.取key的hashCode
      * 2.key的hashCode高16位异或低16位
      * 3.将第一步和第二步得到的结果进行取模运算。
      */
     1 static final int hash(Object key) {
     2         int h;
     3         //计算key的hashCode, h = Objects.hashCode(key)
     4         //h >>> 16表示对h无符号右移16位,高位补0,然后h与h >>> 16按位异或
     5         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
     6     }
     7 
     8     /**
     9      * 如果参数x实现了Comparable接口,返回参数x的类名,否则返回null
    10      */
    11     static Class<?> comparableClassFor(Object x) {
    12         if (x instanceof Comparable) {
    13             Class<?> c;
    14             Type[] ts, as;
    15             Type t;
    16             ParameterizedType p;
    17             if ((c = x.getClass()) == String.class) // bypass checks
    18                 return c;
    19             if ((ts = c.getGenericInterfaces()) != null) {
    20                 for (int i = 0; i < ts.length; ++i) {
    21                     if (((t = ts[i]) instanceof ParameterizedType) &&
    22                             ((p = (ParameterizedType) t).getRawType() ==
    23                                     Comparable.class) &&
    24                             (as = p.getActualTypeArguments()) != null &&
    25                             as.length == 1 && as[0] == c) // type arg is c
    26                         return c;
    27                 }
    28             }
    29         }
    30         return null;
    31     }
    32 
    33     /**
    34      * 如果x的类型为kc,则返回k.compareTo(x),否则返回0
    35      */
    36     @SuppressWarnings({"rawtypes", "unchecked"}) // for cast to Comparable
    37     static int compareComparables(Class<?> kc, Object k, Object x) {
    38         return (x == null || x.getClass() != kc ? 0 :
    39                 ((Comparable) k).compareTo(x));
    40     }
    41 
    42     /**
    43      * 结果为>=cap的最小2的自然数幂
    44      */
    45     static final int tableSizeFor(int cap) {
    46         //先移位再或运算,最终保证返回值是2的整数幂
    47         int n = cap - 1;
    48         n |= n >>> 1;
    49         n |= n >>> 2;
    50         n |= n >>> 4;
    51         n |= n >>> 8;
    52         n |= n >>> 16;
    53         return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    54     }
    /* ---------------- Fields -------------- */
     1  /**
     2      * 哈希桶数组,分配的时候,table的长度总是2的幂
     3      */
     4     transient Node<K, V>[] table;
     5 
     6     /**
     7      * HashMap将数据转换成set的另一种存储形式,这个变量主要用于迭代功能
     8      */
     9     transient Set<Map.Entry<K, V>> entrySet;
    10 
    11     /**
    12      * 实际存储的数量,则HashMap的size()方法,实际返回的就是这个值,isEmpty()也是判断该值是否为0
    13      */
    14     transient int size;
    15 
    16     /**
    17      * hashmap结构被改变的次数,fail-fast机制
    18      */
    19     transient int modCount;
    20 
    21     /**
    22      * HashMap的扩容阈值,在HashMap中存储的Node键值对超过这个数量时,自动扩容容量为原来的二倍
    23      *
    24      * @serial
    25      */
    26     int threshold;
    27 
    28     /**
    29      * HashMap的负加载因子,可计算出当前table长度下的扩容阈值:threshold = loadFactor * table.length
    30      *
    31      * @serial
    32      */
    33     final float loadFactor;

    具体源码参考地址:

    https://github.com/wupeixuan/JDKSourceCode1.8/blob/master/src/java/util/HashMap.java

  • 相关阅读:
    OPENC函数 UF_CSYS UF_MTX UF_VEC (判断矢量平行)(UF_VEC3_is_parallel)
    OPENC函数 UF_CUTTER UF_NCGROUP UF_PARAM(如何创建刀具)(UF_CUTTER_create)
    OPENC函数 (UF_setup UF_ncgroup UF_oper)(创建程序组并创建程序,然后把程序放入组中)(UF_OPER_create)
    OPENC函数 UF_CAM UF_NCGROUP (UF_CAM_opt_ask_types UF_CAM_opt_ask_subtypes UF_NCPROG_create UF_NCGROUP_accept_member)
    OPENC函数UF_UI_ONT UF_OPER (过切检查) (UF_OPER_is_path_gouged)
    OPENC函数 UF_SETUP UF_NCGROUP(获取CAM模块中 程序 机床 几何 加工方法的所有名称)(UF_SETUP_ask_geom_root UF_SETUP_ask_program_root)
    OPENC函数 UF_UI_ONT UF_OPER函数(对当前程序进行操作(获取名称))(UF_UI_ONT_ask_selected_nodes、UF_OPER_ask_cutter_group等)
    OPENC函数 UF_TRNS(平移 变换)( uf5943 , uf5947)
    openstackM版本安装
    openstack及组件简要介绍
  • 原文地址:https://www.cnblogs.com/huststl/p/8628765.html
Copyright © 2011-2022 走看看