HashTable源码分析

Posted 51life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HashTable源码分析相关的知识,希望对你有一定的参考价值。

HashTable,它与HashMap不同之处有两点:1.HashTable是线程安全的 2.HashTable不允须key或者value为null。

1.属性

    /**
     * The hash table data.
     */
// 底层数组
private transient Entry<K,V>[] table; /** * The total number of entries in the hash table.
* Entry元素的个数
*/ private transient int count; /** * The table is rehashed when its size exceeds this threshold. (The * value of this field is (int)(capacity * loadFactor).) * 临界值:当数组中的元素个数大于等于这个数值时,再添加元素就进行扩容操作 * @serial */ private int threshold; /** * The load factor for the hashtable. * 加载因子:数组长度*加载因子 = 临界值 * @serial */ 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结构修改次数,每次添加,更新,删除元素时,这个值就加1 private transient int modCount = 0;

2.构造器

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

3.方法

3.1 put(K key,V value):将指定key映射到此Hash表中的指定value

 
//添加synchronized关键字保证线程安全
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);
// 根据hash值获取下标
int index = (hash & 0x7FFFFFFF) % tab.length;
// 遍历该下标下所有的元素,如果key相等,那么则替换
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; } } modCount++;
// 如果当前数组中元素的个数 大于等于 临界值,进行扩容操作
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 Entry<K,V> e = tab[index]; tab[index] = new Entry<>(hash, key, value, e); count++; return null; }

 进入rehash方法

 protected void rehash() {
        int oldCapacity = table.length;
        Entry<K,V>[] oldMap = table;

        // overflow-conscious code
// 新的容量 = 原来的容量乘以2+1 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; } Entry<K,V>[] newMap = new Entry[newCapacity]; modCount++; threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1); boolean rehash = initHashSeedAsNeeded(newCapacity); table = newMap; // 对原来数组中的所有Entry元素重新排序放到新的数组中 for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; if (rehash) { e.hash = hash(e.key); } int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = newMap[index]; newMap[index] = e; } } }

3.2 remove(K key):从hash表中移除该键及对应的值

 public synchronized V remove(Object key) {
        Entry tab[] = table;
        int hash = hash(key);
// 先根据key值获取对应下标
int index = (hash & 0x7FFFFFFF) % tab.length;
// 循环该下标下所有的元素,找出key的hash值相同,并且e.key.equals(key)的元素,将其删除
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; e.value = null; return oldValue; } } return null; }

3.3 V  get(K key):返回指定键映射的Value值

   public synchronized V get(Object key) {
// 根据key找到对应数组中的下标,然后再将key值和数组中该下标下对应的所有元素进行比较,如果key的哈希值相同,并且key相等,那么该Entry元素就是所要找的 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和HashMap源码部分相差不大,最主要的区别就是HashTable是使用了synchronized关键字,保证了线程安全。

















以上是关于HashTable源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Hashtable源码分析

Hashtable源码分析

HashTable源码分析

Java源码分析HashTable源码分析

Java源码分析HashTable源码分析

Hashtable源码分析