Collection-HashMap详解

HashMap

<K, V>就是他的泛型,

  1. K这个Map所包含的键
  2. V对应映射的类型

概念易错点

  1. 集合的泛型其实是语法糖,他会在编译器转换成对应的类型
HashMap<> map1 = new HashMap<>();
map1.put("k1", obj1);
HashMap<String, Object> map2 = new HashMap<>();
map2.put("k1", obj1);

解析上是一致的。

两个重要概念

  • 没有指明泛型的时候会依照上下文,进行类型推断成对象
  • 前面指明泛型,后面会按照JDK1.7自动进行类型推断
G:\Java\WorkSpace_2017Summer>javap -c Something.class
Compiled from "Something.java"
class Something {
  java.util.HashMap<java.lang.String, java.lang.Object> map1;

  java.util.HashMap map2;

  Something();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: new           #2                  // class java/util/HashMap
       8: dup
       9: invokespecial #3                  // Method java/util/HashMap."<init>":()V
      12: putfield      #4                  // Field map1:Ljava/util/HashMap;
      15: aload_0
      16: new           #2                  // class java/util/HashMap
      19: dup
      20: invokespecial #3                  // Method java/util/HashMap."<init>":()V
      23: putfield      #5                  // Field map2:Ljava/util/HashMap;
      26: return

  void fun();
    Code:
       0: aload_0
       1: getfield      #5                  // Field map2:Ljava/util/HashMap;
       4: ldc           #6                  // String k1
       6: ldc           #7                  // String v1
       8: invokevirtual #8                  // Method java/util/HashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
      11: pop
      12: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #9                  // class Something
       3: dup
       4: invokespecial #10                 // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #11                 // Method fun:()V
      12: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
      15: aload_1
      16: getfield      #5                  // Field map2:Ljava/util/HashMap;
      19: ldc           #6                  // String k1
      21: invokevirtual #13                 // Method java/util/HashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
      24: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      27: return
}

推断成<Object, Object>类型了

源码深度分析

ConcurrentMap<>:

A scalable concurrent ConcurrentNavigableMap implementation. The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.
拓展的并发由ConcurrentNavigableMap实现,map排序按照key的顺序,或者创建时候提供的比较器。

This class implements a concurrent variant of SkipLists providing expected average log(n) time cost for the containsKey, get, put and remove operations and their variants. Insertion, removal, update, and access operations safely execute concurrently by multiple threads.
这个类实现一个了并发变化的SkipLists,为其提供了时间复杂度为log(n)的container,get,put和remove操作。插入,删除,更新和访问操作是多个线程同时安全的执行的。(并发安全的)

HashMap<>:
  1. 负载因子 The load factor for the hash table.在hash table容量自动增长的时候,测量的对比依据
  2. 初始化容量 hash表中初始化的数量
    迭代器性能取决于负载因子(defaulty load factor = 0.75f)和初始化容量(deafaulty capacity = 1 < 4),如果需要高性能,就不要负载因子太低,或者容量太多
  3. 顺序 不保证顺序
  4. null 允许空值和空键 他会计算得到hash为0,取第一个
  5. transient 用transient关键字标记的成员变量不参与序列化过程。
  6. 线程不安全的访问,我们推荐是
    Map m = Collections.synchronizedMap(new HashMap(...));
    
    这个我们本质是全部加sync
Put
 /**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained a mapping for the key, the old
     * value is replaced.
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     * @return the previous value associated with <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     */
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

调用重载总的方法,所有的put都会到这里来

    /**
     * Implements Map.put and related methods
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value 是否覆盖
     * @param evict if false, the table is in creation mode.  创建新的节点
     * @return previous value, or null if none
     */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0) // table 是字段属性 Node<K,V>[] table;
            n = (tab = resize()).length;    // 表为空,就先重新就算长度
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null); // 表中空,就放在Hash表的数组中
        else {  // 否则放在Hash表的链表中
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))  // 表存在Entry
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);  //使用LinkHashMap树节点找到
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);   //遍历到末尾,赋值上去
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))// 链表存在
                        break;
                    p = e;  
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount; //The number of times this HashMap has been structurally modified
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

Node对象

    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;  // 下一个对象

        Node(int hash, K key, V value, Node<K,V> next) {/***/}

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {/***/}

        public final boolean equals(Object o) {/***/}

evict关键字详解主要是用在LinkHashMap中,HashMap未实现

    //The head (eldest) of the doubly linked list.
    void afterNodeInsertion(boolean evict) { // possibly remove eldest
        LinkedHashMap.Entry<K,V> first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true);
        }
    }

HashMap模型

哈希模型

HashMap本质是不安全的,我们推荐使用ConcurrentHashMap

HashSet 对比 HashMap

HashSet本质是使用了HashMap,HashSet = HashMap<E, Object>;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容