hashtable和 hashmap相关知识点

hashtable和 hashmap 源码信息

数据结构初始容量负载因子
hashtable110.75
hashmap160.75
  • hshtable
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.
     */
    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 */
    @java.io.Serial
    private static final long serialVersionUID = 1421746759512286392L;

    /**
     * Constructs a new, empty hashtable with the specified initial
     * capacity and the specified load factor.
     *
     * @param      initialCapacity   the initial capacity of the hashtable.
     * @param      loadFactor        the load factor of the hashtable.
     * @throws     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);

        if (initialCapacity==0)
            initialCapacity = 1;
        this.loadFactor = loadFactor;
        table = new Entry<?,?>[initialCapacity];
        threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
    }

    /**
     * Constructs a new, empty hashtable with the specified initial capacity
     * and default load factor (0.75).
     *
     * @param     initialCapacity   the initial capacity of the hashtable.
     * @throws    IllegalArgumentException if the initial capacity is less
     *              than zero.
     */
    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }

    /**
     * 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 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).
     *
     * @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);
    }
  • hashmap:最大容量 MAXIMUM_CAPACITY
public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {

    /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

    /**
     * The maximum capacity, used if a higher value is implicitly specified
     * by either of the constructors with arguments.
     * MUST be a power of two <= 1<<30.
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * The load factor used when none specified in constructor.
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**
     * The bin count threshold for using a tree rather than list for a
     * bin.  Bins are converted to trees when adding an element to a
     * bin with at least this many nodes. The value must be greater
     * than 2 and should be at least 8 to mesh with assumptions in
     * tree removal about conversion back to plain bins upon
     * shrinkage.
     */
    static final int TREEIFY_THRESHOLD = 8;

    /**
     * The bin count threshold for untreeifying a (split) bin during a
     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
     * most 6 to mesh with shrinkage detection under removal.
     */
    static final int UNTREEIFY_THRESHOLD = 6;

    /**
     * The smallest table capacity for which bins may be treeified.
     * (Otherwise the table is resized if too many nodes in a bin.)
     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
     * between resizing and treeification thresholds.
     */
    static final int MIN_TREEIFY_CAPACITY = 64;

哈希冲突

哈希冲突(Hash Collision):不同的关键字通过同一个哈希函数可能得到同一哈希地址,即 key1 ≠ key2,而 Hash(key1) = Hash(key2),这种现象称为哈希冲突。

解决方案

常用的解决哈希冲突的方式有链地址法开放地址法

扩容

哈希表(Hashtable)在扩容时确实会重新计算所有元素的哈希值,并将它们重新插入到新的更大的数组中。这个过程称为“重新散列”(Rehashing)。尽管如此,扩容操作不会影响原有的数据查询,原因如下:

扩容过程

  1. 创建新数组

    • 创建一个新的、更大的数组来存储哈希表的元素。
  2. 重新散列

    • 遍历当前哈希表中的所有元素。
    • 计算每个元素在新数组中的新位置。
    • 将元素插入到新数组中。
  3. 更新引用

    • 将哈希表的内部引用从旧数组切换到新数组。

不影响原有数据查询的原因

  1. 原子性

    • 扩容操作通常是一个原子操作,即在扩容完成之前,哈希表对外部查询是不可见的。这意味着在扩容过程中,查询操作仍然使用旧数组进行,不会受到影响。
  2. 线程安全

    • 在多线程环境中,哈希表的扩容操作需要确保线程安全。通常会使用锁机制来防止在扩容过程中其他线程的干扰。
  3. 数据一致性

    • 扩容完成后,所有元素都已经重新插入到新数组中,且哈希表的内部引用已经更新。因此,查询操作会立即使用新数组,而不会出现数据丢失或不一致的情况。

示例

假设有一个简单的哈希表,初始容量为4,存储了以下键值对:

  • (1, “A”)
  • (2, “B”)
  • (3, “C”)

当哈希表的负载因子达到阈值(例如0.75)时,哈希表会扩容到新的容量8。扩容过程如下:

  1. 创建一个容量为8的新数组。
  2. 重新计算每个元素的哈希值并插入新数组:
    • (1, “A”) -> 新位置
    • (2, “B”) -> 新位置
    • (3, “C”) -> 新位置
  3. 更新哈希表的内部引用,使其指向新数组。

扩容完成后,查询操作会立即使用新数组,而不会影响原有的数据查询。

注意事项

  • 性能影响:扩容操作虽然不会影响查询结果,但会暂时增加哈希表的性能开销。因此,合理设置初始容量和负载因子可以减少扩容的频率。
  • 线程安全:在多线程环境中,确保扩容操作的线程安全非常重要,通常通过锁机制来实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值