ICode9

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

HashTable源码学习

2022-02-19 14:05:01  阅读:186  来源: 互联网

标签:Hashtable int value 学习 源码 HashTable key Entry hashtable


一.介绍

1.HashMap和HashTable的区别

1.相同点

  • 二者都实现了Map接口。
  • 底层都是哈西表

2.不同点

  • Hashtable继承自Dictionary类,而HashMap继承自AbstractMap类。

  • Hashtable 第一次创建对象的时候就会给底层数组开辟空间 Entry[] 11

    HashMap 创建对象时 没有给底层数组进行空间开辟

  • HashMap把Hashtable的contains方法去掉了。改成containsValue和containsKey

    Hashtable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。

  • Hashtable中,key和value都不允许出现null值

    HashMap中,null可以作为键,这样的键只有一个

  • 哈希值的使用不同,HashTable直接使用对象的hashCode

    HashMap重新计算hash值。

  • HashTable在不指定容量的情况下的默认容量为11

    HashMap为16

  • Hashtable不要求底层数组的容量一定要为2的整数次幂

    HashMap则要求一定为2的整数次幂。

  • Hashtable扩容时,将容量变为原来的2倍加1

    HashMap扩容时,将容量变为原来的2倍。

  • Hashtable 中的方法是Synchronize的。

    HashMap线程不安全

  • 计算index的方法不同:

    • HashTable: index = (hash & 0x7FFFFFFF) % tab.length
    • HashMap:index = hash & (tab.length – 1)

2.HashTable

像HashMap一样,Hashtable在哈希表中存储键/值对。当使用一个哈希表,要指定用作键的对象,以及要链接到该键的值。

然后,该键经过哈希处理,所得到的散列码被用作存储在该表中值的索引

二.源码部分

1.基本属性

继承Dictionary 类

是一个抽象类,用来存储键/值对,作用和Map类相似。

给出键和值,你就可以将值存储在Dictionary对象中。一旦该值被存储,就可以通过它的键来获取它。所以和Map一样, Dictionary 也可以作为一个键/值对列表。

Cloneable是标记型的接口,它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆

java.io.Serializable接口:

可以启用其序列化功能。未实现次接口的类无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。

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

    /**
     * The hash table data.哈希表数据
     */
    private transient Entry<?,?>[] table;

    /**
     * The total number of entries in the hash table.哈希表中enyty的总数
     */
    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).
     */
    private transient int modCount = 0;

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = 1421746759512286392L;
    
        /**
     * The maximum size of array to allocate.
     * 要分配的数组的最大大小。
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2.构造函数

/**
 * 无参构造,默认容量为11,加载因子为0.75
 * Constructs a new, empty hashtable with a default initial capacity (11)
 * and load factor (0.75).
 */
public Hashtable() {
    this(11, 0.75f);
}
/**
 * Constructs a new, empty hashtable with the specified initial capacity
 * and default load factor (0.75).
 * 创建指定大小的哈希表
 * 初始容量用户自定义,加载因子为默认的0.75
 * @param     initialCapacity   the initial capacity of the hashtable.
 * @exception IllegalArgumentException if the initial capacity is less
 *              than zero.
 */
public Hashtable(int initialCapacity) {
    this(initialCapacity, 0.75f);
}
/**
 * Constructs a new, empty hashtable with the specified initial
 * capacity and the specified load factor.
 * 创建了一个指定大小的哈希表,并且通过fillRatio指定填充比例
 * @param      initialCapacity   the initial capacity of the hashtable.
 * @param      loadFactor        the load factor of the hashtable.
 * @exception  IllegalArgumentException  if the initial capacity is less
 *             than zero, or if the load factor is nonpositive.
 */
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);
    //当初始化容量为0的时候,将初始容量设置为1
    if (initialCapacity==0)
        initialCapacity = 1;
    //加载因子赋值
    this.loadFactor = loadFactor;
    //创建一个新的大小为初始容量的enytry数组
    table = new Entry<?,?>[initialCapacity];
    //阈值为initialCapacity * loadFactor或最大值
    threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
}
/**
 * Constructs a new hashtable with the same mappings as the given
 * Map.  The hashtable is created with an initial capacity sufficient to
 * hold the mappings in the given Map and a default load factor (0.75).
 *  第四个构造方法创建了一个以M中元素为初始化元素的哈希表。
 * 哈希表的容量被设置为M的两倍,或是11
 * @param t the map whose mappings are to be placed in this map.
 * @throws NullPointerException if the specified map is null.
 * @since   1.2
 */
public Hashtable(Map<? extends K, ? extends V> t) {
    this(Math.max(2*t.size(), 11), 0.75f);
    putAll(t);
}

3.contains()

/**
 * Tests if some key maps into the specified value in this hashtable.
 * This operation is more expensive than the {@link #containsKey
 * containsKey} method.
 * 测试此映射表中是否存在与指定值关联的键。
 * <p>Note that this method is identical in functionality to
 * {@link #containsValue containsValue}, (which is part of the
 * {@link Map} interface in the collections framework).
 *
 * @param      value   a value to search for
 * @return     <code>true</code> if and only if some key maps to the
 *             <code>value</code> argument in this hashtable as
 *             determined by the <tt>equals</tt> method;
 *             <code>false</code> otherwise.
 * @exception  NullPointerException  if the value is <code>null</code>
 */
public synchronized boolean contains(Object value) {
    //如果传入的value值为空,则抛出异常
    if (value == null) {
        throw new NullPointerException();
    }
    //2层循环遍历数组及其链表
    Entry<?,?> tab[] = table;
    for (int i = tab.length ; i-- > 0 ;) {
        for (Entry<?,?> e = tab[i] ; e != null ; e = e.next) {
            if (e.value.equals(value)) {
                return true;
            }
        }
    }
    return false;
}

4.put()

/**
 * 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>
 *
 * The value can be retrieved by calling the <code>get</code> method
 * with a key that is equal to the original key.
 * 将指定 key 映射到此哈希表中的指定 value。
 * @param      key     the hashtable key
 * @param      value   the value
 * @return     the previous value of the specified key in this hashtable,
 *             or <code>null</code> if it did not have one
 * @exception  NullPointerException  if the key or value is
 *               <code>null</code>
 * @see     Object#equals(Object)
 * @see     #get(Object)
 */
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 = key.hashCode();
    //得到数组下标
    int index = (hash & 0x7FFFFFFF) % tab.length;
    //忽略警告
    @SuppressWarnings("unchecked")
            //将对应的数组元素保留起来
    Entry<K,V> entry = (Entry<K,V>)tab[index];
    //当该位置已有元素,则发生哈希冲突,遍历链表找通过equal方法找到key
    for(; entry != null ; entry = entry.next) {
        if ((entry.hash == hash) && entry.key.equals(key)) {
            //覆盖原来的值
            V old = entry.value;
            entry.value = value;
            //返回原来的值
            return old;
        }
    }

5.addEntry()

private void addEntry(int hash, K key, V value, int index) {
    modCount++;

    Entry<?,?> tab[] = table;
    //如果数组有效值等于阈值,将进行扩容操作,然后在计算新的index
    if (count >= threshold) {
        // Rehash the table if the threshold is exceeded 如果超过阈值,请重新散列表
        rehash();

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

    // Creates the new entry.创建新条目。count++
    @SuppressWarnings("unchecked")
    Entry<K,V> e = (Entry<K,V>) tab[index];
    tab[index] = new Entry<>(hash, key, value, e);
    count++;
}

6.扩容机制

/**
 * Increases the capacity of and internally reorganizes this
 * hashtable,增加hashtable的容量并对其重组
 * in order to accommodate and access its entries more
 * efficiently.
 * 以便高效地访问更多的条目
 * This method is called automatically when the number of keys in the hashtable exceeds this hashtable's capacity and load factor.
 * 当哈希表中的键数超过该哈希表的容量和负载因子时,将自动调用此方法。
 */
@SuppressWarnings("unchecked")
protected void rehash() {
    //先将数组原来的容量保存起来
    int oldCapacity = table.length;
    Entry<?,?>[] oldMap = table;

    // overflow-conscious code
    //新的容量为原来的一半 + 1
    int newCapacity = (oldCapacity << 1) + 1;
    //如果新的容量超出了最大值,则将新容量变为最大值
    if (newCapacity - MAX_ARRAY_SIZE > 0) {
        //如果原来的容量就是最大值则将不扩容,return
        if (oldCapacity == MAX_ARRAY_SIZE)
            // Keep running with MAX_ARRAY_SIZE buckets
            return;
        newCapacity = MAX_ARRAY_SIZE;
    }
    //新建一个新容量大小的数组
    Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];

    modCount++;
    //阈值也重新赋值,如若已经超出最大值,则为MAX_ARRAY_SIZE + 1
    threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    //将table指向新数组
    table = newMap;
    //遍历原来的hashtable,将其拷贝过来
    for (int i = oldCapacity ; i-- > 0 ;) {
        for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
            Entry<K,V> e = old;
            old = old.next;
            //数组下标值不同于hashmap,都重新计算
            int index = (e.hash & 0x7FFFFFFF) % newCapacity;
            e.next = (Entry<K,V>)newMap[index];
            newMap[index] = e;
        }
    }
}

三.总结

  • Hash:是一种信息摘要算法,它还叫做哈希,或者散列。我们平时使用的MD5,SHA1都属于Hash算法,通过输入key进行Hash计算,就可以获取key的HashCode(),比如我们通过校验MD5来验证文件的完整性。
  • Hashtable 实现并发安全的原理是通过 synchronized 关键字
  • 当线程数量增加的时候,Hashtable 的性能会急剧下降,因为每一次修改都需要锁住整个对象,而其他线程在此期间是不能操作的。不仅如此,还会带来额外的上下文切换等开销,所以此时它的吞吐量甚至还不如单线程的情况。

标签:Hashtable,int,value,学习,源码,HashTable,key,Entry,hashtable
来源: https://www.cnblogs.com/ftfty/p/15912406.html

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

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

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

ICode9版权所有