码迷,mamicode.com
首页 > 编程语言 > 详细

java.util.HashMap

时间:2017-09-11 13:12:58      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:stay   pac   higher   ext   fit   after   sim   man   col   

  1. HashMap 如何实现?
  2. put 做了什么?
  3. get 做了什么?
  4. 初始化容量,满载率,扩展?
  5. hash?
  6. 类似的结构及相似处,不同点?

 

load factor 满载率

capacity 容量

threshold 临界值

技术分享

 

技术分享

 

 

import java.util.Map;

public class Test {

    public static void main(String[] args) {
        Map<Key, String> map = new HashMap<Key, String>();
        map.put(new Key("A"), "1");
        map.put(new Key("B"), "2");
        map.put(new Key("C"), "3");
        System.out.println(map);
    }
}

class Key {
    private String name;

    Key(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return 1;
    }

    @Override
    public String toString() {
        return "Key [name=" + name + "]";
    }
}

 

技术分享

 

import java.util.Map;

public class Test {

    public static void main(String[] args) {
        Map<Key, Integer> map = new HashMap<Key, Integer>();
        for (int i = 0; i < 11; i++) {
            map.put(new Key(System.nanoTime()), i);
        }
        System.out.println(map);
    }
}

class Key {
    private long name;

    Key(long name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return 1;
    }

    @Override
    public String toString() {
        return "Key [name=" + name + "]";
    }
}

 

 

    static final int TREEIFY_THRESHOLD = 8;
    static final int UNTREEIFY_THRESHOLD = 6;
    static final int MIN_TREEIFY_CAPACITY = 64;

控制treeify的临界值是8 ,当bin中链大于8时,则尝试treeify

  • 1)如果此时表容量不足64,则会扩表。因此添加第9个元素时,由16->32 ,添加第10个元素时,由32->64
  • 2)添加第11个元素时,此时转为了TreeNode

 技术分享

 

 

 

技术分享

 

 ==============================================

技术分享

技术分享

技术分享

 

put

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        Node<K, V>[] tab;
        Node<K, V> p;
        int n, i;
        // 1 table 为空时重置大小
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        // 2  落到空bin 直接添加节点
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        // 3  落到非空bin ,判断 a , b ,c,
        else {
            Node<K, V> e;
            K k;
            // a) header与入参key相同,替换旧值
            if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            // b) header是红黑树去添加树节点
            else if (p instanceof TreeNode)
                e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
            // c) header是链
            else {
                // 遍历链,逐项检查 ,判断 I ,II
                for (int binCount = 0;; ++binCount) {
                    // I) 末尾追加节点并检查是否需要转为红黑树
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    // II) key相同则替换旧值 返回
                    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;
        // 表中元素个数大于临界值时,扩展表X2
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

 

get

    final Node<K, V> getNode(int hash, Object key) {
        Node<K, V>[] tab;
        Node<K, V> first, e;
        int n;
        K k;
        // table 存在,header节点存在
        if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) {
            // 与 header 节点key相同,返回header 节点
            if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            // 如果存在header的子节点
            if ((e = first.next) != null) {
                // 如果 header 是红黑树去取树节点
                if (first instanceof TreeNode)
                    return ((TreeNode<K, V>) first).getTreeNode(hash, key);
                // 如果 header 是链
                do {
                    // 遍历节点,找到相同key返回
                    if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        // 未查到相同key
        return null;
    }

 

treeify

    final void treeifyBin(Node<K, V>[] tab, int hash) {
        int n, index;
        Node<K, V> e;
        // 如果table达不到最小treeify 容量(64)则扩容X2
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
        // header 节点存在时
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode<K, V> hd = null, tl = null;
            // 遍历链将 Node -> TreeNode
            do {
                TreeNode<K, V> p = replacementTreeNode(e, null);
                if (tl == null)
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
            if ((tab[index] = hd) != null)
                // 绘制红黑树 
                hd.treeify(tab);
        }
    }

 

resize

    /**
     * Initializes or doubles table size.  If null, allocates in
     * accord with initial capacity target held in field threshold.
     * Otherwise, because we are using power-of-two expansion, the
     * elements from each bin must either stay at same index, or move
     * with a power of two offset in the new table.
     *
     * @return the table
     */
    final Node<K, V>[] resize() {
         ...
        return newTab;
    }

 

hash

    /**
     * Computes key.hashCode() and spreads (XORs) higher bits of hash
     * to lower.  Because the table uses power-of-two masking, sets of
     * hashes that vary only in bits above the current mask will
     * always collide. (Among known examples are sets of Float keys
     * holding consecutive whole numbers in small tables.)  So we
     * apply a transform that spreads the impact of higher bits
     * downward. There is a tradeoff between speed, utility, and
     * quality of bit-spreading. Because many common sets of hashes
     * are already reasonably distributed (so don‘t benefit from
     * spreading), and because we use trees to handle large sets of
     * collisions in bins, we just XOR some shifted bits in the
     * cheapest possible way to reduce systematic lossage, as well as
     * to incorporate impact of the highest bits that would otherwise
     * never be used in index calculations because of table bounds.
     */
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

 

关于编写方法时使用的缩略词猜想

  • mc = modCount
  • tab = table
  • bin = table[i]
  • tl = tree left
  • hd = header
  • p = present
  • i = index
  • prev = previous
  • next = next
  • k = key
  • val = value
  • v = value
  • n = length
  • e = entry
  • simple -> simplify
  • tree -> treeify
  • do -> undo
  • untreeify -> untreeify

java.util.HashMap

标签:stay   pac   higher   ext   fit   after   sim   man   col   

原文地址:http://www.cnblogs.com/zno2/p/7500015.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!