zoukankan      html  css  js  c++  java
  • jdk源码+hashmap

    一:集合有哪些

    1、java.lang

    1) Object 1
    2) String 1
    3) AbstractStringBuilder 1
    4) StringBuffer 1
    5) StringBuilder 1
    6) Boolean 2
    7) Byte 2
    8) Double 2
    9) Float 2
    10) Integer 2
    11) Long 2
    12) Short 2
    13) Thread 2
    14) ThreadLocal 2
    15) Enum 3
    16) Throwable 3
    17) Error 3
    18) Exception 3
    19) Class 4
    20) ClassLoader 4
    21) Compiler 4
    22) System 4
    23) Package 4
    24) Void 4
    

    2、java.util

    1) AbstractList 1
    2) AbstractMap 1
    3) AbstractSet 1
    4) ArrayList 1
    5) LinkedList 1
    6) HashMap 1
    7) Hashtable 1
    8) HashSet 1
    9) LinkedHashMap 1
    10) LinkedHashSet 1
    11) TreeMap 1
    12) TreeSet 1
    13) Vector 2
    14) Queue 2
    15) Stack 2
    16) SortedMap 2
    17) SortedSet 2
    18) Collections 3
    19) Arrays 3
    20) Comparator 3
    21) Iterator 3
    22) Base64 4
    23) Date 4
    24) EventListener 4
    25) Random 4
    26) SubList 4
    27) Timer 4
    28) UUID 4
    29) WeakHashMap 4
    二、hashmap
    链表:增删快,查询慢,时间复杂度是O(n)
    数组:查询快,增删慢,时间复杂度是O(1)
    Hashmap=链表+数组+红黑树(在链表超过8,数组长度超过64,变树,链表小于6变回)
    hashmap的查找时间复杂度是O(1)

    put操作的流程:

    第一步:key.hashcode(),时间复杂度O(1)。

    第二步:找到桶以后,判断桶里是否有元素,如果没有,直接new一个entey节点插入到数组中。时间复杂度O(1)。

    第三步:如果桶里有元素,并且元素个数小于6,则调用equals方法,比较是否存在相同名字的key,不存在则new一个entry插入都链表尾部。时间复杂度O(1)+O(n)=O(n)。

    第四步:如果桶里有元素,并且元素个数大于6,则调用equals方法,比较是否存在相同名字的key,不存在则new一个entry插入都链表尾部。时间复杂度O(1)+O(logn)=O(logn)。红黑树查询的时间复杂度是logn。

    实际上每个元素都是装满链表的数组的存储格式
    链表的每个node结构是:hash+map+next(指针),hash是通过hash碰撞出来的hashcode,map是键值对(k,v)
    三、代码
    // 默认容量16
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 
     
    // 最大容量
    static final int MAXIMUM_CAPACITY = 1 << 30;    
     
    // 默认负载因子0.75
    static final float DEFAULT_LOAD_FACTOR = 0.75f; 
     
    // 链表节点转换红黑树节点的阈值, 9个节点转
    static final int TREEIFY_THRESHOLD = 8; 
     
    // 红黑树节点转换链表节点的阈值, 6个节点转
    static final int UNTREEIFY_THRESHOLD = 6;   
     
    // 转红黑树时, table的最小长度
    static final int MIN_TREEIFY_CAPACITY = 64; 
     
    // 链表节点, 继承自Entry
    static class Node<K,V> implements Map.Entry<K,V> {  
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
     
        // ... ...
    }
     
    // 红黑树节点
    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
       
        // ...
    }
    // 代码1
    static final int hash(Object key) { // 计算key的hash值
        int h;
        // 1.先拿到key的hashCode值; 2.将hashCode的高16位参与运算
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    // 代码2
    int n = tab.length;
    // 将(tab.length - 1) 与 hash值进行&运算
    int index = (n - 1) & hash;

    四:经典部分

    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;
        // 1.对table进行校验:table不为空 && table长度大于0 && 
        // table索引位置(使用table.length - 1和hash值进行位与运算)的节点不为空
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            // 2.检查first节点的hash值和key是否和入参的一样,如果一样则first即为目标节点,直接返回first节点
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            // 3.如果first不是目标节点,并且first的next节点不为空则继续遍历
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    // 4.如果是红黑树节点,则调用红黑树的查找目标节点方法getTreeNode
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    // 5.执行链表节点的查找,向下遍历链表, 直至找到节点的key和入参的key相等时,返回该节点
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        // 6.找不到符合的返回空
        return null;
    }
    /**
     * 从调用此方法的节点开始查找, 通过hash值和key找到对应的节点
     * 此方法是红黑树节点的查找, 红黑树是特殊的自平衡二叉查找树
     * 平衡二叉查找树的特点:左节点<根节点<右节点
     */
    final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
        // 1.将p节点赋值为调用此方法的节点,即为红黑树根节点
        TreeNode<K,V> p = this;
        // 2.从p节点开始向下遍历
        do {
            int ph, dir; K pk;
            TreeNode<K,V> pl = p.left, pr = p.right, q;
            // 3.如果传入的hash值小于p节点的hash值,则往p节点的左边遍历
            if ((ph = p.hash) > h)
                p = pl;
            else if (ph < h) // 4.如果传入的hash值大于p节点的hash值,则往p节点的右边遍历
                p = pr;
            // 5.如果传入的hash值和key值等于p节点的hash值和key值,则p节点为目标节点,返回p节点
            else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                return p;
            else if (pl == null)    // 6.p节点的左节点为空则将向右遍历
                p = pr;
            else if (pr == null)    // 7.p节点的右节点为空则向左遍历
                p = pl;
            // 8.将p节点与k进行比较
            else if ((kc != null ||
                      (kc = comparableClassFor(k)) != null) && // 8.1 kc不为空代表k实现了Comparable
                     (dir = compareComparables(kc, k, pk)) != 0)// 8.2 k<pk则dir<0, k>pk则dir>0
                // 8.3 k<pk则向左遍历(p赋值为p的左节点), 否则向右遍历
                p = (dir < 0) ? pl : pr;
            // 9.代码走到此处, 代表key所属类没有实现Comparable, 直接指定向p的右边遍历
            else if ((q = pr.find(h, k, kc)) != null) 
                return q;
            // 10.代码走到此处代表“pr.find(h, k, kc)”为空, 因此直接向左遍历
            else
                p = pl;
        } while (p != null);
        return null;
    }
     
    在无人能够指引的路上,自己就是明灯
  • 相关阅读:
    Mysql字段约束
    MYSQL中数据类型介绍
    Redis常见的几种使用方式及其优缺点
    python解析jason串,数据存入数据库
    redo log
    Oracle控制文件(Control Files)
    笔记
    redis面试题
    mysqldump备份
    超简单的内网穿透技巧(使用花生壳进行内网穿透)
  • 原文地址:https://www.cnblogs.com/vv-lilu/p/15150153.html
Copyright © 2011-2022 走看看