HashTable的源码解读以及HashMap与HashTable的异同点

我们首先说一下有关HashTable的相关内容,HashMap的相关内容可以在上一篇博客中找到。。。

1、HashTable的特点

1)是以键值对的形式存在的

2)底层数据结构是数组+链表

3)key与value均不能为null

4)key 不可以重复,value可以重复

5)不能保证插入的顺序

6)线程安全

2、HashTable源码解读

1)继承关系

public class Hashtable<K,V>

    extends Dictionary<K,V>

    implements Map<K,V>, Cloneable, java.io.Serializable

Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口

2)基本属性

private transient Entry<K,V>[] table;//数组

private transient int count;//键值对的个数

private int threshold;//阈值

private float loadFactor;//加载因子

private transient int modCount = 0

3)扩容机制

protected void rehash() {

        HashtableEntry e, old;

        int i, index;

        int oldCapacity = table.length;

        HashtableEntry oldTable[] = table;

        int newCapacity = oldCapacity * 2 + 1;

        HashtableEntry newTable[] = new HashtableEntry[newCapacity];

        threshold = (int)(newCapacity * loadFactor);

        table = newTable;

        for (i = oldCapacity ; i-- > 0 ;) {

            for (old = oldTable[i] ; old != null ; ) {

                e = old;

                old = old.next;

                index = (e.hash & 0x7FFFFFFF) % newCapacity;

                e.next = newTable[index];

                newTable[index] = e;

            }

        }

    }

class HashtableEntry {

    int hash;

    Object key;

    Object value;

    HashtableEntry next;

 从源码可以看出HashMap的扩容机制是扩容到原数组的2倍+1

4)构造函数

HashMap的构造函数有四种

a.指定容量大小和加载因子的构造函数

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

    }

b.指定“容量大小”的构造函数

public Hashtable(int initialCapacity) {

        this(initialCapacity, 0.75f);

    }

c.默认构造函数,指定的容量大小是11;加载因子是0.75

public Hashtable() {

        this(11, 0.75f);

    }

d.包含“子Map”的构造函数

public Hashtable(Map<? extends K, ? extends V> t) {

        this(Math.max(2*t.size(), 11), 0.75f);

        putAll(t);

    }

5) get()方法:根据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;

    }

6)remove()方法:根据Key删除整个键值对,返回的是该键值对的value值

public synchronized V remove(Object key) {

        Entry tab[] = table;

        int hash = hash(key);

        int index = (hash & 0x7FFFFFFF) % tab.length;

        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;

    }

7)put()方法:添加键值对

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;

        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<K,V> e = tab[index];

        tab[index] = new Entry<>(hash, key, value, e);

        count++;

        return null;

    }

3、HashTable与HashMap的异同点

不同点:

1)继承的类不同

HashTable继承Dictionary

HashMap继承AbstractMap

2)初始数组大小不同

HashTable:11

HashMap:16

3)线程安全问题

HashTable:线程安全

HashMap:非线程安全

HashTable方法是同步的,而HashMap则不是。HashTable中几乎所有的public的方法都是synchronized 的,而有些方法也是在内部通过 synchronized 代码块来实现。

4)扩容的方式不同

HashTable:旧数组的2倍+1

HashMap:旧数组的2倍

HashMap的容量必须是2的指数级大小数据。当初始容量给定时,一般会自动转换成离它最近的一个2的指数的数字,作为它的容量。

5)null值处理不同

HashTable:不允许key与value为null,当用null当做Key的时候会抛出java.lang.NullPointerException异常,因为其在计算Hash的时候调用了key.hashCode();当Key为Null的时候就会抛出异常,而且在put中,并未单独对null进行判断(key不能重复)

HashMap:key可以为null,有且只有一个,value可以由多个为null。

6)hash函数不同

HashTable

 private int hash(Object k) {

        // hashSeed will be zero if alternative hashing is disabled.

        return hashSeed ^ k.hashCode();

    }

HashMap

final int hash(Object k) {

        int h = hashSeed;

        if (0 != h && k instanceof String) {

            return sun.misc.Hashing.stringHash32((String) k);

        }

        h ^= k.hashCode();

        h ^= (h >>> 20) ^ (h >>> 12);

        return h ^ (h >>> 7) ^ (h >>> 4);

    }

7)支持的遍历种类不同

HashMap只支持Iterator(迭代器)遍历。

而Hashtable支持Iterator(迭代器)和Enumeration(枚举器)两种方式遍历

8) contains()方法

Hashtable支持contains(Object value)方法,而且重写了toString()方法;

而HashMap不支持contains(Object value)方法,没有重写toString()方法。

相同点:

1)底层均是数组+链表

2)扩容时机相同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值