前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java集合-Hashtable源码解析-JDK1.8

Java集合-Hashtable源码解析-JDK1.8

作者头像
Java学习录
发布2019-04-18 15:03:22
3380
发布2019-04-18 15:03:22
举报
文章被收录于专栏:Java学习录Java学习录

Hashtable简介

推荐查看此篇文章之前首先查看 HashMap源码分析 效果更佳哦

与HashMap的数组加链表加红黑树不同,Hashtable在jdk 1.8中仅仅使用了数组+链表的方式进行存储。

HashMap的属性

HashMap的一些基础属性:

代码语言:javascript
复制
/**     * 保村数据的数组     */    private transient Entry<?, ?>[] table;
    /**     * 数组的元素数量     */    private transient int count;
    /**     * 扩容阈值     *     * @serial     */    private int threshold;
    /**     * 加载因子     */    private float loadFactor;
    /**     * 被修改的次数     */    private transient int modCount = 0;
    /**     * use serialVersionUID from JDK 1.0.2 for interoperability     */    private static final long serialVersionUID = 1421746759512286392L;    /**     *最大容量     */    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

HashMap存储数据所使用的链表数据结构:

代码语言:javascript
复制
private static class Entry<K, V> implements Map.Entry<K, V> {        final int hash;        final K key;        V value;        Hashtable.Entry<K, V> next;
        protected Entry(int hash, K key, V value, Hashtable.Entry<K, V> next) {            this.hash = hash;            this.key = key;            this.value = value;            this.next = next;        }    }

Hashtable的构造方法

代码语言:javascript
复制
 /**     * 指定初始容量和加载因子     */    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);    }
    /**     * 指定初始容量,加载因子使用默认的0.75     */    public Hashtable(int initialCapacity) {        this(initialCapacity, 0.75f);    }
    /**     * 默认构造方法     */    public Hashtable() {        this(11, 0.75f);    }
    /**     * 添加一个map     */    public Hashtable(Map<? extends K, ? extends V> t) {        this(Math.max(2 * t.size(), 11), 0.75f);        putAll(t);    }

Hashtable的添加方法

代码语言:javascript
复制
/**     * 添加方法     */    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;        //计算key的哈希值        int hash = key.hashCode();        //计算key应该放的索引        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry<K, V> entry = (Entry<K, V>) tab[index];        //如果存在值则替换        for (; entry != null; entry = entry.next) {            if ((entry.hash == hash) && entry.key.equals(key)) {                V old = entry.value;                entry.value = value;                return old;            }        }        //不存在调用具体的添加方法        addEntry(hash, key, value, index);        return null;    }     private void addEntry(int hash, K key, V value, int index) {        //修改次数增加        modCount++;
        Entry<?, ?> tab[] = table;        //判断是否需要扩容        if (count >= threshold) {            // Rehash the table if the threshold is exceeded            rehash();
            tab = table;            //对本次添加的元素重新计算hash            hash = key.hashCode();            index = (hash & 0x7FFFFFFF) % tab.length;        }
// Creates the new entry.        @SuppressWarnings("unchecked")        Entry<K, V> e = (Entry<K, V>) tab[index];        tab[index] = new Entry<>(hash, key, value, e);        count++;    }

Hashtable的扩容

代码语言:javascript
复制
  /**     * 扩容方法     */    @SuppressWarnings("unchecked")    protected void rehash() {        int oldCapacity = table.length;        Entry<?, ?>[] oldMap = table;
        // 尝试扩容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<?, ?>[] newMap = new Entry<?, ?>[newCapacity];
        modCount++;        // 计算新的扩容阈值        threshold = (int) Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);        table = newMap;        // 转移原结构中数据到新结构中        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;
                int index = (e.hash & 0x7FFFFFFF) % newCapacity;                e.next = (Entry<K, V>) newMap[index];                newMap[index] = e;            }        }    }

Hashtable的查找

代码语言:javascript
复制
  /**     * 查找方法     */    @SuppressWarnings("unchecked")    public synchronized V get(Object key) {        Entry<?, ?> tab[] = table;        //计算哈希        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        //遍历单向链表        for (Entry<?, ?> e = tab[index]; e != null; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                return (V) e.value;            }        }        return null;    }

查找时先定位键值对所在的桶的位置,然后再对链表或红黑树进行查找

Hashtable的删除

代码语言:javascript
复制
/**     * 删除方法     */    public synchronized V remove(Object key) {        Entry<?, ?> tab[] = table;        //计算hash        int hash = key.hashCode();        int index = (hash & 0x7FFFFFFF) % tab.length;        @SuppressWarnings("unchecked")        Entry<K, V> e = (Entry<K, V>) tab[index];        //遍历链表删除        for (Entry<K, V> 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;    }

看了Hashtable的增删改查方法你就明白了为什么他是线程安全的了这哥们的方法都是使用synchronize修饰的。

鉴于篇幅有限,本篇文章仅列出上方部分代码,Hashtable完整源码解析请点击下方“阅读原文”查看!!!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java学习录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档