`

HashTable

阅读更多
Hashtable


一、对比HashMap

1.
项目HashMapHashtable
默认容量1611
负载因子0.750.75
null值允许key/value为空不允许key/value为空(put操作时报空指针异常)
扩容length*2length*2+1
安全线程不安全线程安全
extendsAbstractMapDictionary
容量>=12^n


2.负载因子
过低,空间利用率低,频繁的扩容
过高,寻址时间增加,key value 的多了;

3.快速失败
modCount

在遍历过程中,如果 modCount > expectedCount
throw new ConcurrentModificationException

二、类定义

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


三、属性

1.源码
    /**
     * The hash table data.
     */
    // Entry 的数组,Entry 
    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 */
    private static final long serialVersionUID = 1421746759512286392L;



四、构造方法

1.
    // 初始化容量,负载因子
    public Hashtable(int initialCapacity, float loadFactor) {
        // 初始化容量不能小于0
	if (initialCapacity < 0)
	    throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        // 负载因子不能小于0且其是 float类型的数据
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal Load: "+loadFactor);

        if (initialCapacity==0)
        // 初始化容量 为任意数字 ,HashMap 要求必须为 2 的 N 次幂
            initialCapacity = 1;
	this.loadFactor = loadFactor;
	table = new Entry[initialCapacity];
	threshold = (int)(initialCapacity * loadFactor);
    }


2.
    // 默认负载因子 0.75
    public Hashtable(int initialCapacity) {
	this(initialCapacity, 0.75f);
    }

    /**
     * Constructs a new, empty hashtable with a default initial capacity (11)
     * and load factor (0.75).
     */
    // 默认初始化容量 11 
    public Hashtable() {
	this(11, 0.75f);
    }



3.以存在的集合作为参数

    /**
     * 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) {
        // 调用构造方法,初始化容量为  已有集合中的key-value 对数量的 2 倍
	this(Math.max(2*t.size(), 11), 0.75f);
	putAll(t);
    }

    // 遍历已有集合,调用put方法,synchronized 关键字,线程安全
    public synchronized void putAll(Map<? extends K, ? extends V> t) {
        for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
            put(e.getKey(), e.getValue());
    }



五、put()

1.源码
    
    public synchronized V put(K key, V value) {
	// Make sure the value is not null

        // value 不允许为空,空指针异常
	if (value == null) {
	    throw new NullPointerException();
	}

	// Makes sure the key is not already in the hashtable.
        // 赋值
	Entry tab[] = table;

        // key 不能为空,否则获取 hashcode 时报空指针异常
        // 一次hash,key本身的hash值
	int hash = key.hashCode();
        // 二次计算hash值,再与length 取余,确定存放在数组中的位置
	int index = (hash & 0x7FFFFFFF) % tab.length;
        // 取出index 位置的数据,遍历数组下的链表,判断此 key 是否已存在
        // 若已存在,则替换已存在的value值,并返回旧的value值
	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;
	    }
	}
        // 操作次数加 1 
	modCount++;
        // Hashtable 中 Entry 的数量 count 是否大于临界值
	if (count >= threshold) {
	    // Rehash the table if the threshold is exceeded
            // 扩容
	    rehash();

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

	// Creates the new entry.
        // 将 tab[index] 位置的链表赋值给 e
	Entry<K,V> e = tab[index];
        // 新增Entry ,将原有的链表放在新加入的Entry 的next 中
        // 即 新增的Entry 是放在链表的首位的
	tab[index] = new Entry<K,V>(hash, key, value, e);
	count++;
	return null;
    }

    // Entry 的构造方法
	protected Entry(int hash, K key, V value, Entry<K,V> next) {
	    this.hash = hash;
	    this.key = key;
	    this.value = value;
	    this.next = next;
	}
     
    // 扩容
    protected void rehash() {
        // 扩容前的容量
	int oldCapacity = table.length;
	Entry[] oldMap = table;
        // 扩容后的容量 length*2 + 1 
	int newCapacity = oldCapacity * 2 + 1;
	Entry[] newMap = new Entry[newCapacity];
        // 操作次数加1 
	modCount++;
	threshold = (int)(newCapacity * loadFactor);
	table = newMap;

        // 两层循环,外层遍历原数组的总长度,将旧数组依次放入新的数组中
	for (int i = oldCapacity ; i-- > 0 ;) {
            // 获取旧数据中下标 i 处的链表
	    for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
                // 获取链表当前位置的元素值
		Entry<K,V> e = old;
                // 指针下移
		old = old.next;
                // 计算存储位置
		int index = (e.hash & 0x7FFFFFFF) % newCapacity;
                // 当前元素指向新的数组中 index 下标位置
		e.next = newMap[index];
                // 新数组的index 位置指向 e 
		newMap[index] = e;
	    }
            // 遍历的结果是将链表中的元素倒置放入新的数组中
	}
    }
    


六、remove()
1.源码
    public synchronized V remove(Object key) {
	Entry tab[] = table;
	int hash = key.hashCode();
        // 定位存储位置
	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++;
              // 若链表中的元素数量 > 1 ,则将前一个Entry.next 指向 当前元素的next
		if (prev != null) {
		    prev.next = e.next;
		} else {
                    // 遍历条件
                    // Entry<K,V> e = tab[index], prev = null
                    // 下一次循环时,进行赋值 prev = e ;若 prev == null 
                    // 说明链表中的第一个Entry 即为目标
		    tab[index] = e.next;
		}
		count--; // count表示存放的 Entry的数量
		V oldValue = e.value;
		e.value = null;
		return oldValue;
	    }
	}


七、get()

1.源码

    public synchronized V get(Object key) {
	Entry tab[] = table;
        // key 不能为 null,此处报空指针
	int hash = key.hashCode();
	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;
    }
分享到:
评论

相关推荐

    C# json 转hashtable

    var hashtable = (Hashtable)serializer.Deserialize(jsonString, typeof(Hashtable)); ``` 2. **Newtonsoft.Json**:这是更流行和功能强大的第三方库,也被称为Json.NET。它的`JsonConvert.DeserializeObject`方法...

    hashMap和hashTable的区别

    ### hashMap和hashTable的区别 #### 一、简介与基本概念 `HashMap` 和 `HashTable` 都是 Java 集合框架中非常重要的数据结构,它们都实现了 `Map` 接口,用于存储键值对。尽管它们在功能上有很多相似之处,但在...

    WinFormHashTable最简单用法,.net hashtable ,hashtable ,hashtable用法

    哈希表(Hashtable)是.NET框架中的一种常用数据结构,主要用作键值对存储,它提供了快速的数据存取方式。在WinForm应用程序中,我们可能会利用Hashtable来管理各种对象,尤其是在需要高效查找和操作数据时。下面将...

    HashMap和HashTable的区别和不同

    ### HashMap与HashTable的区别详解 #### 引言 在Java编程中,`HashMap`与`HashTable`作为两种常用的数据结构,经常被用来存储键值对数据。尽管它们在功能上相似,但在实现细节、性能表现以及使用场景方面存在显著...

    经典讲解List和ArrayList和Vector和HashTable和HashMap区别

    在Java编程语言中,集合框架是处理对象数组的重要工具,其中`List`、`ArrayList`、`Vector`、`HashTable`和`HashMap`是五个关键的接口和类,它们各有不同的特性和用途。以下是这些概念的详细解释: 1. **List接口**...

    Json字符串转换Hashtable,DataTable,DataSet方法和反转换方法

    Hashtable hashtable = JsonConvert.DeserializeObject&lt;Hashtable&gt;(json); ``` 上述代码将JSON字符串解析成一个Hashtable对象,键值对可以直接通过键来访问。 接下来,我们讨论JSON到DataTable的转换。同样需要...

    asp.net遍历hashtable

    在ASP.NET中,Hashtable是一种常用的数据结构,它是一个键值对集合,允许程序员存储和检索对象。本篇文章将深入探讨如何在ASP.NET中遍历Hashtable,以及相关的重要知识点。 首先,理解Hashtable的基本概念至关重要...

    HashMap和HashTable底层原理以及常见面试题

    HashMap和HashTable底层原理以及常见面试题 HashMap和HashTable是Java中两个常用的数据结构,都是基于哈希表实现的,但它们之间存在着一些关键的区别。本文将深入探讨HashMap和HashTable的底层原理,并总结常见的...

    HashMap与HashTable和HashSet的区别

    ### HashMap与HashTable和HashSet的区别 #### 一、概述 在Java集合框架中,`HashMap`, `HashTable` 和 `HashSet` 是三个重要的数据结构,它们分别实现了`Map`接口和`Set`接口,提供了不同的功能来满足不同的编程...

    hashtable存储数据.rar

    在Java编程语言中,`Hashtable`是一个非常基础且重要的数据结构,它属于集合框架的一部分,提供了键值对(key-value pairs)的存储功能。`Hashtable`类是线程安全的,意味着在多线程环境下,它能确保数据的一致性和...

    C#-Hashtable应用

    Hashtable是C#编程语言中的一种内置数据结构,属于.NET Framework的System.Collections命名空间。它是一个基于散列的键值对集合,允许程序员快速查找、添加和删除元素。在本篇文档中,我们将深入探讨如何在C#中有效...

    java Hashtable的泛型化

    在Java编程语言中,`Hashtable`是`Collections`框架的一部分,它是一个同步的键值对存储容器。在早期的Java版本中,`Hashtable`并没有直接支持泛型,这意味着你可以在其中存储任何类型的键(`Object`)和值(`Object...

    HashMap与HashTable区别

    ### HashMap与HashTable的区别 在Java编程语言中,`HashMap`和`HashTable`是两种非常重要的数据结构,它们都实现了`Map`接口,并提供了键值对的存储方式。这两种数据结构虽然相似,但在实现细节和使用场景上存在...

    C#中哈希表(HashTable)用法实例详解(添加/移除/判断/遍历/排序等)

    哈希表(HashTable)在C#编程语言中是一种常用的数据结构,它允许高效地存储和检索键值对数据。在.NET Framework中,`System.Collections`命名空间提供了`HashTable`类,用于存储和管理这些键值对。下面我们将深入探讨...

    hashmap与hashtable区别

    ### HashMap与Hashtable的区别 在Java编程语言中,`HashMap`和`Hashtable`是两种非常重要的数据结构,它们都用于存储键值对。然而,在实际应用过程中,这两种数据结构有着本质的不同,下面将详细介绍这些差异。 ##...

    hashtable序列化与反序列化

    本文将详细探讨标题所提及的“hashtable序列化与反序列化”,并提供一个基本的示例。 首先,让我们理解什么是序列化。序列化是将对象的状态转换为可存储或可传输的形式的过程。在Java中,对象序列化允许我们将一个...

    hashtable和hashmap的区别

    ### Hashtable和HashMap的区别 在Java编程语言中,`Hashtable`和`HashMap`是两种非常重要的数据结构,它们都实现了`Map`接口,用于存储键值对。尽管它们有着相似的功能,但在实现细节和应用场景上存在显著差异。接...

    哈希表hashtable实现

    在本篇文章中,我们将深入探讨哈希表的实现,特别是基于C语言的简单实现,参考文件"hashtable.c"和"hashtable.h"。 1. 哈希函数:哈希表的核心是哈希函数,它将输入(键或关键字)转换为数组索引。一个好的哈希函数...

    用Session、Hashtable实现购物车功能

    本教程将详细讲解如何使用Java中的Session和Hashtable来实现这一功能。 首先,Session是Web应用程序中用于跟踪用户状态的一种机制。在HTTP协议无状态的特性下,Session为我们提供了在多个请求之间保持用户信息的...

Global site tag (gtag.js) - Google Analytics