美文网首页
Hashtable源码笔记

Hashtable源码笔记

作者: T_log | 来源:发表于2018-08-28 16:58 被阅读33次

Hashtable概述

  1. Hashtable是和HashTable一样都是存储key-value数据结构的集合容器
  2. HashMap不可以存储key和value为null的数据
  3. 存储key-value的Entry对象实际上是一个单向链表

基本参数

//存储key-value键值对的Entry数组
//Hashtable采用散列法进行存储,每个Entry实际上就是一个单向链表
private transient Entry<K,V>[] table;

//table中的数据总数
private transient int count;

/**
* The table is rehashed when its size exceeds this threshold.  (The
* value of this field is (int)(capacity * loadFactor).)
*/
//hashtable rehash的阀值
private int threshold;

//加载因子
private float loadFactor;

/**
* The number of times this Hashtable has been structurally modified
* Structural modifications are those that change the number of entries in
* the Hashtable or otherwise modify its internal structure (e.g.,
* rehash).  This field is used to make iterators on Collection-views of
* the Hashtable fail-fast.  (See ConcurrentModificationException).
*/
//Hashtable被修改的次数,fail-fast
private transient int modCount = 0;

/**
 *Hashtable仓位和加载因子的构造器
 *
 */
public Hashtable(int initialCapacity, float loadFactor) {
        //校验仓位
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        //校验加载因子
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);
        //条件初始化
        if (initialCapacity==0)
            initialCapacity = 1;
        
        this.loadFactor = loadFactor;
        //根据初始容量进行初始化
        table = new Entry[initialCapacity];
        //阀值为(初始容量与加载因子的乘积)与系统默认阀值中的最小值
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        initHashSeedAsNeeded(initialCapacity);
    }
/**
 * 默认根据指定初始容量+默认0.75(折中)的构造器
 */
public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }

//初始容量为11,加载因子为0.75的构造器
public Hashtable() {
        this(11, 0.75f);
    }

/**
* 参数为一个map的构造器,其中Map的key和value类型分别继承Map<K,V>的K\V类型
* 去参数map即t容量大小的两倍和11中最大的,也就是说,该map最小容量也是11
* 将t中的值全部放入新构造的map中
*/
public Hashtable(Map<? extends K, ? extends V> t) {
        this(Math.max(2*t.size(), 11), 0.75f);
        putAll(t);
    }

//table的大小
public synchronized int size() {
        return count;
    }

//table的容量是否为空
public synchronized boolean isEmpty() {
        return count == 0;
    }

//返回Hashtable的所有key的枚举对象
public synchronized Enumeration<K> keys() {
        return this.<K>getEnumeration(KEYS);
    }

//返回Hashtable所有的Values的枚举对象
public synchronized Enumeration<V> elements() {
        return this.<V>getEnumeration(VALUES);
    }

//是否包含value值
public synchronized boolean contains(Object value) {
        if (value == null) {
            throw new NullPointerException();
        }

        Entry tab[] = table;
        for (int i = tab.length ; i-- > 0 ;) {
            for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
                if (e.value.equals(value)) {
                    return true;
                }
            }
        }
        return false;
    }

//hashtable是否包含key
public synchronized boolean containsKey(Object key) {
        Entry tab[] = table;
        int hash = hash(key);
        int index = (hash & 0x7FFFFFFF) % tab.length;
        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                return true;
            }
        }
        return false;
    }

//根据指定key获取对应的value
public synchronized V get(Object key) {
    Entry tab[] = table;
    int hash = hash(key);
    int index = (hash & 0x7FFFFFFF) % tab.length;
    for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
        if ((e.hash == hash) && e.key.equals(key)) {
            return e.value;
        }
    }
    return null;
}

//当重置Hashtable容量时,需要重新rehash
 protected void rehash() {
        //原table大小
        int oldCapacity = table.length;
        //原table
        Entry<K,V>[] oldMap = table;

        // overflow-conscious code
        //扩容后的大小
        int newCapacity = (oldCapacity << 1) + 1;
        //如果扩容后的大小大于最大值,则取最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            if (oldCapacity == MAX_ARRAY_SIZE)
                // Keep running with MAX_ARRAY_SIZE buckets
                return;
            newCapacity = MAX_ARRAY_SIZE;
        }
        //新建map用于rehash后存储数据
        Entry<K,V>[] newMap = new Entry[newCapacity];

        //用于标记Hashtable被修改的次数+1
        modCount++;
        //修改阀值的大小,新容器大小乘加载因子和允许最大容量中取较小值
        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
        // TODO 
        boolean rehash = initHashSeedAsNeeded(newCapacity);

        //将表的指针指向新建的map地址
        table = newMap;

        //遍历原table,将值重新hash后计算出新的index,放入新的table中, 从后向前进行插入
        for (int i = oldCapacity ; i-- > 0 ;) {
            for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
                Entry<K,V> e = old;
                //同一个index上的(hash值相同)的数据
                old = old.next;

                if (rehash) {
                    e.hash = hash(e.key);
                }
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                e.next = newMap[index];
                newMap[index] = e;
            }
        }
    }

     /**
        * Maps the specified <code>key</code> to the specified
        * <code>value</code> in this hashtable. Neither the key nor the
        * value can be <code>null</code>. <p>
        * 将KEY对应的value放入hashtabl中。KEY和VALUE都不能为空
        */
    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }

        // Makes sure the key is not already in the hashtable.
        Entry tab[] = table;
        int hash = hash(key);
        int index = (hash & 0x7FFFFFFF) % tab.length;
        //如果KEY已经存在,则value进行覆盖
        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                V old = e.value;
                e.value = value;
                return old;
            }
        }

        //修改表示进行+1
        modCount++;
        //如果容器总的数量已经达到阀值,则进行rehash操作
        if (count >= threshold) {
            // Rehash the table if the threshold is exceeded
            rehash();

            tab = table;
            hash = hash(key);
            index = (hash & 0x7FFFFFFF) % tab.length;
        }

        // Creates the new entry.
        //创建新的Entry用于存放新的KEY-VALUE键值对
        Entry<K,V> e = tab[index];
        tab[index] = new Entry<>(hash, key, value, e);
        //容量进行+1
        count++;
        //如果KEY已经存在则返回原KEY对应的value,否则返回NULL
        return null;
    }

     /**
        * Removes the key (and its corresponding value) from this
        * hashtable. This method does nothing if the key is not in the hashtable.
        * 将该hashtable中的KEY以及对应的value进行删除
        */
    public synchronized V remove(Object key) {
        //先拿到this的hashtable
        Entry tab[] = table;
        //对key进行hash操作,获取该KY对应的index
        int hash = hash(key);
        int index = (hash & 0x7FFFFFFF) % tab.length;
        //如果该index有多个entry,则进行遍历寻找后进行删除
        for (Entry<K,V> e = tab[index], prev = null ; e != null ; prev = e, e = e.next) {
            if ((e.hash == hash) && e.key.equals(key)) {
                modCount++;
                if (prev != null) {
                    prev.next = e.next;
                } else {
                    tab[index] = e.next;
                }
                count--;
                V oldValue = e.value;
                //help GC
                e.value = null;
                return oldValue;
            }
        }
        return null;
    }


    /**
     * Clears this hashtable so that it contains no keys.
     * 清除hashtable中的数据
     */
    public synchronized void clear() {
        Entry tab[] = table;
        modCount++;
        for (int index = tab.length; --index >= 0; )
            tab[index] = null;
        count = 0;
    }

参考
http://www.cnblogs.com/xingele0917/p/3815370.html
http://www.cnblogs.com/jilodream/
https://www.cnblogs.com/skywang12345/p/3310887.html
http://www.importnew.com/24822.html

相关文章

  • Hashtable源码笔记

    Hashtable概述 Hashtable是和HashTable一样都是存储key-value数据结构的集合容器H...

  • Hashtable源码解析

    1、本文主要内容 Hashtable简介 Hashtable源码剖析 总结 今天来总结下 Hashtable,Ha...

  • 00_Hashtable学习

    Hashtable源码分析 基于Java8Hashtable.class的说明: This class imple...

  • HashMap和Hashtable

    1. Hashtable 1.1 定义 从源码中可以看到,Hashtable继承了Dictionary,...

  • Java 集合类原理

    Java基础——HashMap源码分析 Java基础——HashSet源码分析 Java基础——HashTable...

  • Java基础之LinkedHashMap源码解析

    Java集合源码解析系列 Java基础之HashMap源码解析 Java基础之HashTable源码解析 Java...

  • ConcurrentHashMap 原理和源码分析(一)

    通过之前几篇文章《HashMap原理和源码分析》 《HashTable原理和源码分析》《LinkedHashMap...

  • java源码-Hashtable

    开篇  Hashtable作为jdk提供的最原始的key/value存储结构,属于线程安全系列的,所以这边顺便把这...

  • Hashtable源码分析

    集合特性 对于集合框架我们的关注点一般在一下几点: 集合底层实现的数据结构是什么 数组+链表 集合中元素是否允许...

  • Hashtable源码研究

    上几篇笔记研究了HashMap和LinkedHashMap,此笔记研究Hashtable。一:概述先来看下Hash...

网友评论

      本文标题:Hashtable源码笔记

      本文链接:https://www.haomeiwen.com/subject/mqsqwftx.html