zoukankan      html  css  js  c++  java
  • HashTable与LinkedHashMap

    HashTable的特点
    HashTable继承自Dictionary类,Dictionary 类是一个抽象类,在JDK 1.0中提供用来存储键/值对,作用和Map类相似。

    HashTable类中,其数据结构与HashMap是相同的。依然是采用“链地址法”实现的哈希表,保存实际数据的,依然是Entry对象。
    Entry<K,V> implements Map.Entry<K,V> {
    int hash;
    final K key;
    V value;
    Entry<K,V> next;
    }

    和HashMap很类似
    不同点:
    1、HashTable是线程安全的(synchronized),HashMap线程不安全
    2、HashTable是key和value不能为null,而HashMap允许key和value为空。
    3、使用的迭代器不同,Hashtable的迭代器(enumerator)。

    put方法
    put方法的主要逻辑如下:
    1. 先获取synchronized锁。
    2. put方法不允许null值,如果发现是null,则直接抛出异常(key和value都不能为null)。
    3. 计算key的哈希值和index
    4. 遍历对应位置的链表,如果发现已经存在相同的hash和key,则更新value,并返回旧值。
    5. 如果不存在相同的key的Entry节点,则增加节点。在新增节点时,考虑是否需要扩容,如果需要则进行扩容,之后添加新节点到链表头部。

    rehash扩容方法
    数组长度增加一倍((oldCapacity << 1) + 1)(如果超过上限,则设置成上限值)。
    更新哈希表的扩容限值。
    遍历旧表中的节点,计算在新表中的index,插入到对应位置链表的头部

    get方法
    1. 先获取synchronized锁。
    2. 计算key的哈希值和index。
    3. 在对应位置的链表中寻找具有相同hash和key的节点,返回节点的value。
    4. 如果遍历结束都没有找到节点,则返回null。

    remove方法
    1. 先获取synchronized锁。
    2. 计算key的哈希值和index。
    3. 在对应位置的链表中寻找具有相同hash和key的节点,将该key对应的节点从当前链表中删除。
    4. 如果遍历结束都没有找到节点,则返回null。

    LinkedHashMap

     继承自HashMap。

    适用场景:
    存储的数据是键值对,且需要保证数据按插入顺序有序的话需要使用LinkedHashMap。

                                                  数据存储结构

    重写了void init()方法:

    void init() {
    //创建了一个hash=-1,key,value,next都为null的Entry
            header = new Entry<>(-1, null, null, null);
    //让创建的Entry的before和after都指向自身(其实就是创建了一个职业头部节点的双向链表)
            header.before = header.after = header;
        }

    属性:accessOrder  (默认是false)

    true:按照访问顺序组织数据 

    false: 按照插入顺序组织数据  

    当accessOrder属性为默认时,进行get操作:

     

     当accessOrder属性为true时,进行get操作:(会按照访问得顺序重新排列)

     

    put方法(重要)

    它么有重写put方法,只是重写了 void addEntry(),void createEntry(),这两方法,从而实现它的双链表结构。

    public V put(K key, V value) {
    //先判断当前的Entry[] 数组是否为空数组
            if (table == EMPTY_TABLE) {
                inflateTable(threshold); //如果为空,对表进行初始化
            }
    //判断key键是否为空
            if (key == null)
                return putForNullKey(value);   //在HashMap中允许value值为空
            int hash = hash(key);  //计算key的hash值
            int i = indexFor(hash, table.length); //通过哈希值和当前的数据长度,计算出在数组的存放位置
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                Object k;
    //如果计算的hash值位置有值,并且key值相同,覆盖原来的value,将原值返回
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }
    
            modCount++;
            addEntry(hash, key, value, i);  //存放值的具体实现,LinkedHashMap重写了其方法
            return null;
        }
    
    
    //重写
    void addEntry(int hash, K key, V value, int bucketIndex) {
            super.addEntry(hash, key, value, bucketIndex);//先调用父类的方法
    
    //删除最近最少使用元素的策略定义
            // Remove eldest entry if instructed
            Entry<K,V> eldest = header.after;
            if (removeEldestEntry(eldest)) {
                removeEntryForKey(eldest.key);
            }
        }
    
    
    //调用的父类的addEntry()方法
    void addEntry(int hash, K key, V value, int bucketIndex) {
            if ((size >= threshold) && (null != table[bucketIndex])) {
                resize(2 * table.length);
                hash = (null != key) ? hash(key) : 0;
                bucketIndex = indexFor(hash, table.length);
            }
            createEntry(hash, key, value, bucketIndex);//将新元素以双向链表的形式加入
        }
    
    
    //重写
    void createEntry(int hash, K key, V value, int bucketIndex) {
            HashMap.Entry<K,V> old = table[bucketIndex];
            Entry<K,V> e = new Entry<>(hash, key, value, old);
            table[bucketIndex] = e;
            e.addBefore(header); // 调用元素的addBrefore方法,将元素加入到哈希、双向链接列表。
            size++;
        }

      以上部分源码基于JDK1.7。

  • 相关阅读:
    PLSQL中使用二维存储结构---二维数组
    重启并发管理器
    Jackson优化使用实例
    Java日志管理:Logger.getLogger()和LogFactory.getLog()的区别(详解Log4j)
    Java泛型简明教程
    理解JSON:3分钟课程
    java 电子书下载地址
    JAVA开发中相对路径,绝对路径全面总结
    Java关键字synchronized详解
    52 个超实用网站
  • 原文地址:https://www.cnblogs.com/128-cdy/p/12298606.html
Copyright © 2011-2022 走看看