zoukankan      html  css  js  c++  java
  • HashMap存储过程分析

    1:hashMap的实现原理

      1.1 hsahMap在jdk1.8的时候做了一个改进,在jdk1.7的时候hahsMap是基于哈希表(数组+链表)实现的,在1.8之后又加了一个叫二叉树的一个实现,在二叉树里边用了一个叫红黑树,红黑树是二叉树里边的一种,它主要是用来保证树的平衡性,因为二叉树有的时候节点太长,有的时候节点太短,太长的话就不便于遍历,所以说,红黑树的这个目的是来标记(红,黑)的这个算法,主要是保证这棵树的左右两端的平衡,这样遍历的话平均的这个性能就会很好,接下来看一下源码

    2:源码分析

        2.1首先我们看一下他的默认构造方法   

        public HashMap() {
            this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
        }
    

      我们把DEFAULT_LOAD_FACTOR点开,我们可以看到,他默认赋了一个0.75的一个值,这个值是加载因子,还有他的初始化容量数组是16,指的是数组的百分之75都被存了值,就表示这个空间的数据已经存满了,如果满的话这个数组就有可能会去重新创建,就是说这个数组要重新扩充了,这个0.75就是标准的红线,他的内部回去计算这个0.75,他是这样计算的,初始化容量数组默认是16,因子是百分之75,当数组到12的时候就已经存满了,当然了它还提供了别的构造方法,在初始化的时候我们也可以去修改这个值

        /**
         * The default initial capacity - MUST be a power of two. 初始化数组值默认为16
         */
        static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    
            /**
         * The load factor used when none specified in constructor. 加载因子默认为0.75
         */
        static final float DEFAULT_LOAD_FACTOR = 0.75f;
    

       2.2:如何把对象存储到哈希表中,他的存储方法叫PUT,PUT方法的时候我们传入一个key,一个value,调用的是一个putvalue的方法,putvalue里边还调用了一个hash(key)的一个方法,是通过key来计算 hash的值

        

        public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }

      他是先拿到Object的一个对象去求(key.hashCode)对象的值,h就拿到了Object key值,h右移16位在和hashCode疑惑最后得出一个整数,这个整数代表的是这个hash 的值

        static final int hash(Object key) {
            int h;
            return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        }

      得到整个整数以后,他就传到了putval这个方法,我们捡重要的去看一下,首先看一下,下边的一个table,这个table就是Node的这个数组,table其实就是node的一个对象数组,node就是hash里边的一个静态类,里边hash就是我们求的值,next是一个链表,然后把key和value,他把key和value存在了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;

    我们可以看到他判断了一下,如果table=null或table=0那么table就等于resize()方法,里边进行了扩容还有一些判断如果他们都等于空,他会把默认的,他会把默认的数组长度16赋值给他,那么n就等于16,我们看一下他存储的位置,(n-1)=15 ,15&hash赋值给i,tab接收作为数组的下标进行存储到Node,Node是一个链表,存储的对象很多,如果又一个对象存储进来了求的值跟他一样就是形成一个链表,jdk1.8之前就是用这个链表处理的,但是1.8之后,出现了红黑树,来限制这种链表,他这个判读是这样写的(binCount>=TREEIFY_THRESHOLD-1)那么(THREEIFY_THRESHOLD)就等于7,下一个数据就是等于8,当大于8的时候就转换成了红黑树

     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;
        }
    

    3.存储过程

     3.1 刚才进行源码分析,我想大家也了解到了他的一个存储过程,在这里我在总结一下:

        把key通过通过hash()方法计算hash的值,然后这个hash的值对数组进行求余数(默认16),来决定KEY对象在数组中的位置,当这个对象有多个值时,以链表方式进行存储,jdk8以后当链表长度大于8时,链表将转换成红黑树结构存储,这样的目的,是为了取值更快,存储的数量越多性能的表现就越明显。

  • 相关阅读:
    获取项目路径
    Form提交时隐藏Token验证
    属性路由参数约束
    使用Cookie来统计浏览次数,当天重复刷新不增加
    图片上传预览 支持html5的浏览器
    icheck.min.js 选中效果
    bootstrap-modal.js 居中问题
    七十二、SAP中内表的修改,添加条件语句,多条目修改
    七十一、SAP中内表的修改,改一行数据,或一行的某个字段
    七十、SAP中内表批量指定位置插入
  • 原文地址:https://www.cnblogs.com/zhaoyuwei/p/9286665.html
Copyright © 2011-2022 走看看