zoukankan      html  css  js  c++  java
  • JAVA-容器(5)-Map

    (基于JDK1.8源码分析)

    一,Map接口

      Map以键值对方式存储,key具有唯一性,元素顺序根据具体实现类不同,如:treeMap确保了存入顺序而hashMap没有确保存入顺序

      源码分析:

    public interface Map<K,V> {
        
        int size();
        boolean isEmpty();
        boolean containsKey(Object key);
        boolean containsValue(Object value);
        V get(Object key);
        V put(K key, V value);
        V remove(Object key);
        void putAll(Map<? extends K, ? extends V> m);
        void clear();
    
        //返回键值视图
        Set<K> keySet();
        Collection<V> values();
        Set<Map.Entry<K, V>> entrySet();
    
        /** 内部接口*/
        interface Entry<K,V> {
    
            K getKey();
            V getValue();
            V setValue(V value);
            boolean equals(Object o);
            int hashCode();
    
            /***/
            public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
                return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> c1.getKey().compareTo(c2.getKey());
            }
            /***/
            public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
                return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> c1.getValue().compareTo(c2.getValue());
            }
            /***/
            public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
                Objects.requireNonNull(cmp);
                return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
            }
            /***/
            public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
                Objects.requireNonNull(cmp);
                return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
            }
        }
    
        // Comparison and hashing
        boolean equals(Object o);
        int hashCode();
    
        // Defaultable methods
        /***/
        default V getOrDefault(Object key, V defaultValue) {
            V v;
            return (((v = get(key)) != null) || containsKey(key))
                ? v
                : defaultValue;
        }
        /***/
        default void forEach(BiConsumer<? super K, ? super V> action) {
            Objects.requireNonNull(action);
            for (Map.Entry<K, V> entry : entrySet()) {
                K k;
                V v;
                try {
                    k = entry.getKey();
                    v = entry.getValue();
                } catch(IllegalStateException ise) {
                    // this usually means the entry is no longer in the map.
                    throw new ConcurrentModificationException(ise);
                }
                action.accept(k, v);
            }
        }
        /***/
        default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            Objects.requireNonNull(function);
            for (Map.Entry<K, V> entry : entrySet()) {
                K k;
                V v;
                try {
                    k = entry.getKey();
                    v = entry.getValue();
                } catch(IllegalStateException ise) {
                    // this usually means the entry is no longer in the map.
                    throw new ConcurrentModificationException(ise);
                }
    
                // ise thrown from function is not a cme.
                v = function.apply(k, v);
    
                try {
                    entry.setValue(v);
                } catch(IllegalStateException ise) {
                    // this usually means the entry is no longer in the map.
                    throw new ConcurrentModificationException(ise);
                }
            }
        }
        /***/
        default V putIfAbsent(K key, V value) {
            V v = get(key);
            if (v == null) {
                v = put(key, value);
            }
    
            return v;
        }
        /***/
        default boolean remove(Object key, Object value) {
            Object curValue = get(key);
            if (!Objects.equals(curValue, value) ||
                (curValue == null && !containsKey(key))) {
                return false;
            }
            remove(key);
            return true;
        }
        /***/
        default boolean replace(K key, V oldValue, V newValue) {
            Object curValue = get(key);
            if (!Objects.equals(curValue, oldValue) ||
                (curValue == null && !containsKey(key))) {
                return false;
            }
            put(key, newValue);
            return true;
        }
        /***/
        default V replace(K key, V value) {
            V curValue;
            if (((curValue = get(key)) != null) || containsKey(key)) {
                curValue = put(key, value);
            }
            return curValue;
        }
        /***/
        default V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            Objects.requireNonNull(mappingFunction);
            V v;
            if ((v = get(key)) == null) {
                V newValue;
                if ((newValue = mappingFunction.apply(key)) != null) {
                    put(key, newValue);
                    return newValue;
                }
            }
    
            return v;
        }
        /***/
        default V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            Objects.requireNonNull(remappingFunction);
            V oldValue;
            if ((oldValue = get(key)) != null) {
                V newValue = remappingFunction.apply(key, oldValue);
                if (newValue != null) {
                    put(key, newValue);
                    return newValue;
                } else {
                    remove(key);
                    return null;
                }
            } else {
                return null;
            }
        }
        /***/
        default V compute(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            Objects.requireNonNull(remappingFunction);
            V oldValue = get(key);
    
            V newValue = remappingFunction.apply(key, oldValue);
            if (newValue == null) {
                // delete mapping
                if (oldValue != null || containsKey(key)) {
                    // something to remove
                    remove(key);
                    return null;
                } else {
                    // nothing to do. Leave things as they were.
                    return null;
                }
            } else {
                // add or replace old mapping
                put(key, newValue);
                return newValue;
            }
        }
        /***/
        default V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            Objects.requireNonNull(remappingFunction);
            Objects.requireNonNull(value);
            V oldValue = get(key);
            V newValue = (oldValue == null) ? value :
                       remappingFunction.apply(oldValue, value);
            if(newValue == null) {
                remove(key);
            } else {
                put(key, newValue);
            }
            return newValue;
        }
    }

        【1】Map-新增删除

        V put(K key, V value);
         V remove(Object key);
         void putAll(Map<? extends K, ? extends V> m);
         void clear();

       【2】Map-访问

       Set<K> keySet();                  //所有key
        Collection<V> values();           //所有value
        Set<Map.Entry<K, V>> entrySet();   //所有键值对

         Map中没有定义Iterator迭代器,只能根据返回的键值集合Set和Collection的迭代器进行Map的遍历访问

      Iterator keyValuePairs = aMap.entrySet().iterator();
      Iterator keys = aMap.keySet().iterator();
      Iterator values = aMap.values().iterator();

       【3】Map对象的比较

       boolean equals(Object o);
        int hashCode();

       【4】Map分类

        1,通用Map,用于映射管理

      HashMap
      Hashtable
      Properties
      LinkedHashMap
      IdentityHashMap
      TreeMap
      WeakHashMap
      ConcurrentHashMap

        2,专用Map,一般通过其他类才能访问的Map 

      java.util.jar.Attributes
      javax.print.attribute.standard.PrinterStateReasons
      java.security.Provider
      java.awt.RenderingHints
      javax.swing.UIDefaults

        3,Map抽象实现类

      AbstractMap

        4,哈希映射技术

        哈希映射内部使用数组存储元素,因此存在一个用于任意键访问数组元素的访问机制,这个机制称为哈希函数;

        Map中使用哈希函数hashCode()将对象转成整数进行计算后,通过该整数将对象映射到数组中;

        int hashvalue = Maths.abs(key.hashCode()) % table.length;     //将哈希值转正然后和数组大小取余

         5,hashCode分析

          特点:Object及子类都有的方法; 

                   对象通过hashCode计算得出的数值包含了对象物理地址,字符串内容等对象特征信息, 因此对象通过equals比较相等的HashCode也相等;

          作用:

            <1>能够记录对象物理地址信息

            <2>通过对hashCode计算,比如在HashMap中可以作为对象插入数组的索引,利于HashMap元素的存储性能

          其他:

            哈希算法又名散列算法,将数据通过一定的算法指定到一个特定的地址上

            集合添加元素的时先根据hashcode判断存储的物理地址,如果该地址没有其他元素直接存储,如果有其他元素进行equals比较,如果相同不存储,如果不同重新进行散列

            两个对象equals相等,hashCode一定相等; hashCode相等不一定equals相等;

            equals方法重写hashCode方法也需要重写;

          String类的hashCode源码分析:

          String的hashCode是通过对象内容计算而来
      //String的hashCode是通过对象内容计算而来
      public
    int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }

          String的equals比较的是对象内容

      public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String)anObject;
                int n = value.length;
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                            return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
        }

    二,HashMap实现

      定义:基于哈希表的Map接口实现,键值允许为null,不能保证存入顺序和已存储顺序不变;

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

      【1】底层实现

        HashMap底层由数组和链表实现,利用了数组寻址快的优点和链表容易插入和删除的优点来提高HashMap的操作性能;

        1,HashMap内部实现了一个静态内部类Node,主要含有key,value,next(下一个键值对的引用)等属性;

        2,HashMap内部定义了一个Node类型的数组;

        3,HashMap通过该Node类型的数组实现了底层数组组合链表的存储结构

      /** 数组 */
        transient Node<K,V>[] table;
      /** 链表 */
        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) {
                this.hash = hash;
                this.key = key;
                this.value = value;
                this.next = 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) {
                V oldValue = value;
                value = newValue;
                return oldValue;
            }
    
            public final boolean equals(Object o) {
                if (o == this)
                    return true;
                if (o instanceof Map.Entry) {
                    Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                    if (Objects.equals(key, e.getKey()) &&
                        Objects.equals(value, e.getValue()))
                        return true;
                }
                return false;
            }
        }

        【2】构造方法

      /** 1,根据指定容量和负载因子构造HashMap */
        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);
            this.loadFactor = loadFactor;
            this.threshold = tableSizeFor(initialCapacity);
        }
    
        /** 2,根据指定容量构造HashMap */
        public HashMap(int initialCapacity) {
            this(initialCapacity, DEFAULT_LOAD_FACTOR);
        }
    
        /** 3,使用默认负载因子构造HashMap */
        public HashMap() {
            this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
        }
    
        /** 4,根据指定Map对象构造HashMap */
        public HashMap(Map<? extends K, ? extends V> m) {
            this.loadFactor = DEFAULT_LOAD_FACTOR;
            putMapEntries(m, false);
        }

       【3】,插入元素

      /** 将键值对存入HashMap */
        public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
    
        /** 键值对存入HashMap的具体实现*/
        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)
                n = (tab = resize()).length;
            if ((p = tab[i = (n - 1) & hash]) == null)
                tab[i] = newNode(hash, key, value, null);
            else {
                Node<K,V> e; K k;
                if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                    e = p;
                else if (p instanceof TreeNode)
                    e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                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;
            if (++size > threshold)
                resize();
            afterNodeInsertion(evict);
            return null;
        }

        1,hash冲突

        

        2,hash不冲突

        【4】读取元素

        

      /** 根据key获取HashMap的值 */
        public V get(Object key) {
            Node<K,V> e;
            return (e = getNode(hash(key), key)) == null ? null : e.value;
        }
    
        /** */
        final Node<K,V> getNode(int hash, Object key) {
            Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
            if ((tab = table) != null && (n = tab.length) > 0 &&
                (first = tab[(n - 1) & hash]) != null) {
                if (first.hash == hash && // always check first node
                    ((k = first.key) == key || (key != null && key.equals(k))))
                    return first;
                if ((e = first.next) != null) {
                    if (first instanceof TreeNode)
                        return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                            return e;
                    } while ((e = e.next) != null);
                }
            }
            return null;
        }

        【5】删除元素

        

      /** 根据key移除HashMap中的键值对 */
        public V remove(Object key) {
            Node<K,V> e;
            return (e = removeNode(hash(key), key, null, false, true)) == null ?
                null : e.value;
        }
    
        /** */
        final Node<K,V> removeNode(int hash, Object key, Object value,
                                   boolean matchValue, boolean movable) {
            Node<K,V>[] tab; Node<K,V> p; int n, index;
            if ((tab = table) != null && (n = tab.length) > 0 &&
                (p = tab[index = (n - 1) & hash]) != null) {
                Node<K,V> node = null, e; K k; V v;
                if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                    node = p;
                else if ((e = p.next) != null) {
                    if (p instanceof TreeNode)
                        node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
                    else {
                        do {
                            if (e.hash == hash &&
                                ((k = e.key) == key ||
                                 (key != null && key.equals(k)))) {
                                node = e;
                                break;
                            }
                            p = e;
                        } while ((e = e.next) != null);
                    }
                }
                if (node != null && (!matchValue || (v = node.value) == value ||
                                     (value != null && value.equals(v)))) {
                    if (node instanceof TreeNode)
                        ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
                    else if (node == p)
                        tab[index] = node.next;
                    else
                        p.next = node.next;
                    ++modCount;
                    --size;
                    afterNodeRemoval(node);
                    return node;
                }
            }
            return null;
        }
    
        /** HashMap元素清空 */
        public void clear() {
            Node<K,V>[] tab;
            modCount++;
            if ((tab = table) != null && size > 0) {
                size = 0;
                for (int i = 0; i < tab.length; ++i)
                    tab[i] = null;
            }
        }

        【6】HashMap优化

          1,容量调整:

            由于新数组的容量变了,原数组的数据就必须重新计算其再数组中的位置,并放入(resize),这是最消耗性能的地方;

            元素大小 > 数组大小 * 负载因子时HashMap就会进行扩容;

            解决:预测HashMap大小

          2,负载因子

            用于控制何时调整HashMap容量的参数

        【7】快速失败机制

           http://www.cnblogs.com/wanhua-wu/p/6653796.html   (【8】Fail-fast(快速失败机制)

        【8】迭代遍历

          http://www.cnblogs.com/wanhua-wu/p/6653796.html  (【9】迭代器

  • 相关阅读:
    Python 2.x版本和Python3.x版本的不同
    如何给澳洲路局写信refound罚金,遇到交通罚款怎么办
    Java 用自带dom解析器遍历叶子节点内容
    更改Xampp-sql的默认密码-配置appche运行环境
    TSP旅行商问题的Hopfield求解过程
    神经网络hopfield的学习
    分类器的组合算法提升准确率概要
    因子分析——主成份算法实现补充
    因子分析——主成份算法实现
    主成分分析PCA的前世今生
  • 原文地址:https://www.cnblogs.com/wanhua-wu/p/6658040.html
Copyright © 2011-2022 走看看