ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java集合-哈希表HashTable

2021-04-18 12:03:23  阅读:173  来源: 互联网

标签:index hash 哈希 value HashTable key Entry java null


一、简介

HashTable也是一种key-value结构,key-value不允许null,并且这个类的几乎全部的方法都加上了synchronized锁,来保证并发安全,由于加了锁所以性能方面会比较低。

二类图

image

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable

也实现了Map接口,继承了java.util.Dictionary类,Dictionary类是一个抽象类,它定义了键映射到值的数据结构。

常用方法

添加单个元素 synchronized V put(K key, V value)

//添加单个元素
    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {//value值非空判断
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry<?,?> tab[] = table;

        //拿到key的hash值
        int hash = key.hashCode();
        //数组长度取模运算得到下标index
        int index = (hash & 0x7FFFFFFF) % tab.length;

        @SuppressWarnings("unchecked")
        Entry<K,V> entry = (Entry<K,V>)tab[index];//通过index下标取得节点entry

        for(; entry != null ; entry = entry.next) {//单链表entry开始遍历
            //判断链表节点的hash跟key是否跟传入的key匹配
            if ((entry.hash == hash) && entry.key.equals(key)) {
                V old = entry.value;//找到对应链表节点,替换value值
                entry.value = value;
                return old;
            }

        }

        //没有在链表中找到key存在的节点,单链表进行添加
        addEntry(hash, key, value, index);
        return null;
    }
    //链表添加元素
    private void addEntry(int hash, K key, V value, int index) {
        modCount++;//修改次数+1

        Entry<?,?> tab[] = table;

        if (count >= threshold) {//HashTable长度超过了 阈值,进行扩容
            // Rehash the table if the threshold is exceeded
            rehash();//扩容

            //从新计算扩容后 新加入的元素在新数组的下标
            tab = table;
            hash = key.hashCode();
            index = (hash & 0x7FFFFFFF) % tab.length;
        }

        // Creates the new entry.
        @SuppressWarnings("unchecked")
        Entry<K,V> e = (Entry<K,V>) tab[index];//根据下标取得链表节点

        //链表头插
        tab[index] = new Entry<>(hash, key, value, e);
        count++;//长度+1
    }

    //扩容
    protected void rehash() {
        int oldCapacity = table.length;//旧的数组长度
        Entry<?,?>[] oldMap = table;//旧的数组

        // overflow-conscious code
        //新数组的容量=旧数组长度*2+1
        int newCapacity = (oldCapacity << 1) + 1;

        //判断新数组长度是否超过了最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            if (oldCapacity == MAX_ARRAY_SIZE)//旧数组长度超过了最大值,直接return; 后面扩容代码不走了
                // Keep running with MAX_ARRAY_SIZE buckets
                return;
            newCapacity = MAX_ARRAY_SIZE;//新数组长度 超过了最大值,赋值设置的数组最大值
        }

        //创建一个新的数组,长度是newCapacity
        Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];

        modCount++;//修改次数+1
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);//计算下一次扩容的阈值

        table = newMap;//新数组赋值给 HashTable

        //第一层for循环遍历 旧的数组
        for (int i = oldCapacity ; i-- > 0 ;) {
            //第二层for循环遍历,旧数组对应的单链表
            for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;//旧节点e
                old = old.next;//链表下一个节点,用来判断是否终止第二层循环

                //计算旧链表的hash 在新数组的位置
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                //旧节点 的next指向,新数组的下标的链表,头插
                e.next = (Entry<K,V>)newMap[index];
                newMap[index] = e;//节点赋值给新数组
            }
        }
    }

根据key获取元素 synchronized V get(Object key)

//获取元素的值
    public synchronized V get(Object key) {
        //HashTable的数组
        Entry<?,?> tab[] = table;
        //取得key的hash
        int hash = key.hashCode();
        //hash取模运算得到数组下标
        int index = (hash & 0x7FFFFFFF) % tab.length;

        //循环遍历链表节点的hash值和key是否等于 传的参数key,匹配成功返回value值
        for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return (V)e.value;
            }
        }
        return null;//没找到值,返回null
    }

删除元素

    //删除元素 synchronized V remove(Object key)
    public synchronized V remove(Object key) {
        //HashTable的数组
        Entry<?,?> tab[] = table;
        //取得key的hash
        int hash = key.hashCode();
        //hash取模运算得到数组下标
        int index = (hash & 0x7FFFFFFF) % tab.length;

        //根据下标取得链表
        Entry<K,V> e = (Entry<K,V>)tab[index];

        //这个for循环写的666,专门备注一下
        /**
         for语句格式(循环语句)
         for(初始化语句;判断条件语句;控制条件语句){
         循环体语句;
         }

         执行过程:

        (1)执行初始化语句
        (2)执行判断条件语句,看返回值
                 若是true,则继续执行;
                 若是false,则循环结束。
        (3)执行循环体语句
        (4)执行控制条件语句
        (5)回到(2)继续执行语句
         **/

        /**
         初始化语句: Entry<K,V> prev = null
            只是 定义参数 prev

         判断条件语句:e != null
            判断链表不为空

         控制条件语句:prev = e, e = e.next
            第一遍循环完给 初始化语句定义的参数prev 赋值
            在把参数e 指向下一个链表节点
         */
        for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {

            //判断这个链表节点的hash跟key是否跟传入的参数key 相等
            if ((e.hash == hash) && e.key.equals(key)) {
                modCount++;//修改次数+1

                //执行链表删除操作
                if (prev != null) {
                    prev.next = e.next;//把记录了上一个节点prev 的next指向当前要删除的节点的下一个节点
                } else { //等于 false 说明匹配到了第一个节点,直接把首节点的下一个节点赋值给数组即可
                    tab[index] = e.next;//
                }
                count--;//HashTable长度-1
                //临时变量oldValue接收value并返回
                V oldValue = e.value;
                e.value = null;//等于null gc回收
                return oldValue;
            }
        }
        return null;//HashTable没有这个key返回null
    }

标签:index,hash,哈希,value,HashTable,key,Entry,java,null
来源: https://www.cnblogs.com/x-kq/p/14673120.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有