Java中的Hashtable
Hashtable类实现了哈希表,可以将键映射到值。任何非空对象都可以用作键或值。要成功地从哈希表中存储和检索对象,作为键使用的对象必须实现hashCode方法和equals方法。
java.util.Hashtable类是Java中提供的一种键值数据结构,类似于Map接口。它是最初的Java集合框架的一部分,并在Java 1.0中引入。
然而,Hashtable类自引入集合框架以来已被认为过时,并且通常不建议使用。这是因为它是在引入集合框架之前设计的,没有实现Map接口,这使得它难以与框架的其他部分一起使用。此外,Hashtable类是同步的,与Map接口的其他实现相比,可能导致性能较慢。
一般建议使用Map接口或其实现之一(例如HashMap或ConcurrentHashMap)而不是Hashtable类。
以下是使用Hashtable类的示例:
import java.util.Enumeration;
import java.util.Hashtable;
public class Main {
public static void main(String[] args) {
Hashtable<String, Integer> hashtable = new Hashtable<>();
//将元素添加到Hashtable中
hashtable.put("A", 1);
hashtable.put("B", 2);
hashtable.put("C", 3);
//从Hashtable中获取值
int valueA = hashtable.get("A");
System.out.println("A的值: " + valueA);
//从Hashtable中删除元素
hashtable.remove("B");
//枚举Hashtable的元素
Enumeration<String> keys = hashtable.keys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
System.out.println("键: " + key + ", 值: " + hashtable.get(key));
}
}
}
输出结果:
A的值: 1
键: A, 值: 1
键: C, 值: 3
总之,虽然Hashtable类仍然存在于Java中并且仍然可以使用,但一般建议使用Map接口或其实现。
Hashtable的特点:
- 它类似于HashMap,但是是同步的。
- Hashtable将键/值对存储在哈希表中。
- 在Hashtable中,我们指定用作键的对象以及我们要将其关联的值。然后,将哈希了的键,并使用得到的哈希码作为存储值在表中的索引。
- Hashtable类的初始默认容量为11,而loadFactor为0.75。
- HashMap不提供任何枚举,而Hashtable提供不会立即失败的枚举。
声明:
public class Hashtable extends Dictionary implements Map, Cloneable, Serializable
类型参数:
- K - 此映射所维护的键的类型。
- V - 映射的值的类型。
Hashtable的继承关系

Hashtable实现了Serializable、Cloneable和Map<K,V>接口,并扩展了Dictionary<K,V>。直接子类是Properties和UIDefaults。
构造函数:
为了创建Hashtable,我们需要从 java.util.Hashtable 导入它。有许多种方法可以创建Hashtable。
1. Hashtable(): 它创建一个具有默认装载因子0.75和初始容量为11的空哈希表。
Hashtable<K,V> ht = new Hashtable<K,V>();
// Java program to demonstrate
// adding elements to Hashtable
import java.io.*;
import java.util.*;
class AddElementsToHashtable {
public static void main(String args[])
{
// No need to mention the
// Generic type twice
Hashtable<Integer,String> ht1 = new Hashtable<>();
// Initialization of a Hashtable
// using Generics
Hashtable<Integer,String> ht2
= new Hashtable<Integer,String>();
// Inserting the Elements
// using put() method
ht1.put(1,"one");
ht1.put(2,"two");
ht1.put(3,"three");
ht2.put(4,"four");
ht2.put(5,"five");
ht2.put(6,"six");
// Print mappings to the console
System.out.println("Mappings of ht1 : "+ht1);
System.out.println("Mappings of ht2 : "+ht2);
}
}
输出
Mappings of ht1 : {3=three, 2=two, 1=one}
Mappings of ht2 : {6=six, 5=five, 4=four}
2. Hashtable(int initialCapacity): 它创建具有初始大小为initialCapacity并且默认装载因子为0.75的哈希表。
Hashtable<K,V> ht = new Hashtable<K,V>(int initialCapacity);
// Java program to demonstrate
// adding elements to Hashtable
import java.io.*;
import java.util.*;
class AddElementsToHashtable {
public static void main(String args[])
{
// No need to mention the
// Generic type twice
Hashtable<Integer,String> ht1 = new Hashtable<>(4);
// Initialization of a Hashtable
// using Generics
Hashtable<Integer,String> ht2
= new Hashtable<Integer,String>(2);
// Inserting the Elements
// using put() method
ht1.put(1,"one");
ht1.put(2,"two");
ht1.put(3,"three");
ht2.put(4,"four");
ht2.put(5,"five");
ht2.put(6,"six");
// Print mappings to the console
System.out.println("Mappings of ht1 : "+ht1);
System.out.println("Mappings of ht2 : "+ht2);
}
}
输出
Mappings of ht1 : {3=three, 2=two, 1=one}
Mappings of ht2 : {4=four, 6=six, 5=five}
3. Hashtable(int size, float fillRatio): 此版本创建一个哈希表,其初始大小由size指定,填充率由fillRatio指定。 填充率:基本上,它确定哈希表在调整大小之前可以填满多满,其值在0.0到1.0之间。
Hashtable<K,V> ht = new Hashtable<K,V>(int size, float fillRatio);
//Java程序演示
//向哈希表中添加元素
import java.io.*;
import java.util.*;
class AddElementsToHashtable {
public static void main(String args[])
{
//无需再次指定
//泛型类型
Hashtable<Integer, String> ht1
= new Hashtable<>(4, 0.75f);
//使用泛型初始化哈希表
Hashtable<Integer, String> ht2
= new Hashtable<Integer, String>(3, 0.5f);
//使用put()方法插入元素
ht1.put(1, "one");
ht1.put(2, "two");
ht1.put(3, "three");
ht2.put(4, "four");
ht2.put(5, "five");
ht2.put(6, "six");
//打印哈希映射到控制台
System.out.println("ht1的映射:" + ht1);
System.out.println("ht2的映射:" + ht2);
}
}
输出结果
ht1的映射:{3=three, 2=two, 1=one}
ht2的映射:{6=six, 5=five, 4=four}
**4. Hashtable(Map <? extends K,? extends V> m): ** 这将创建一个由m中的元素初始化的哈希表。
Hashtable<K, V> ht = new Hashtable<K, V>(Map m);
//Java程序演示
//向哈希表添加元素
import java.io.*;
import java.util.*;
class AddElementsToHashtable {
public static void main(String args[])
{
//无需再次指定
//泛型类型
Map<Integer, String> hm = new HashMap<>();
//使用put()方法插入元素
hm.put(1, "one");
hm.put(2, "two");
hm.put(3, "three");
//使用泛型初始化哈希表
Hashtable<Integer, String> ht2
= new Hashtable<Integer, String>(hm);
//打印哈希映射到控制台
System.out.println("ht2的映射:" + ht2);
}
}
输出结果
ht2的映射:{3=three, 2=two, 1=one}
示例:
//Java程序演示
//Java.util.Hashtable
import java.util.*;
public class GFG {
public static void main(String[] args)
{
//创建空Hashtable
Hashtable<String, Integer> ht = new Hashtable<>();
//向哈希表添加元素
ht.put("vishal", 10);
ht.put("sachin", 30);
ht.put("vaibhav", 20);
//打印哈希表大小和内容
System.out.println("map的大小是:-" + ht.size());
System.out.println(ht);
//检查键是否存在以及是否存在,如果有,则打印它的值
if (ht.containsKey("vishal")) {
Integer a = ht.get("vishal");
System.out.println("\"vishal\"键的值是: " + a);
}
}
}
输出结果
map的大小是:- 3
{vaibhav=20, vishal=10, sachin=30}
"vishal"键的值是: 10
在Hashtable上执行各种操作
1. 添加元素: 为了向哈希表中添加一个元素,我们可以使用put()方法。然而,哈希表中不会保留插入顺序。在内部,对于每个元素,生成一个单独的哈希,并根据此哈希对元素进行索引,使其更加有效。
// 演示向Hashtable添加元素的Java程序
import java.io.*;
import java.util.*;
class AddElementsToHashtable {
public static void main(String args[])
{
// 不需要两次提及泛型
Hashtable ht1 = new Hashtable<>();
// 使用泛型初始化Hashtable
Hashtable ht2 = new Hashtable();
// 使用put()方法插入元素
ht1.put(1, "Geeks");
ht1.put(2, "For");
ht1.put(3, "Geeks");
ht2.put(1, "Geeks");
ht2.put(2, "For");
ht2.put(3, "Geeks");
// 打印映射到控制台
System.out.println("Mappings of ht1 : " + ht1);
System.out.println("Mappings of ht2 : " + ht2);
}
}
输出
Mappings of ht1 : {3=Geeks, 2=For, 1=Geeks}
Mappings of ht2 : {3=Geeks, 2=For, 1=Geeks}
2. 修改元素: 在添加元素后,如果我们希望更改元素,则可以使用put()方法再次添加元素。由于hashtable中的元素是使用键进行索引的,因此可以通过为我们希望更改的键插入更新后的值来更改键的值。
// 演示更新Hashtable的Java程序
import java.io.*;
import java.util.*;
class UpdatesOnHashtable {
public static void main(String args[])
{
// 初始化Hashtable
Hashtable ht = new Hashtable();
// 使用put方法插入元素
ht.put(1, "Geeks");
ht.put(2, "Geeks");
ht.put(3, "Geeks");
// 打印初始映射到控制台
System.out.println("Initial Map " + ht);
// 更新键2的值
ht.put(2, "For");
// 打印更新后的映射到控制台
System.out.println("Updated Map " + ht);
}
}
输出
Initial Map {3=Geeks, 2=Geeks, 1=Geeks}
Updated Map {3=Geeks, 2=For, 1=Geeks}
3. 移除元素: 为了从Map中移除一个元素,我们可以使用remove()方法。如果对应于该键的映射存在于Map中,则此方法取key值并删除该键的映射。
// 从Hashtable中删除映射的Java程序
import java.io.*;
import java.util.*;
class RemovingMappingsFromHashtable {
public static void main(String args[])
{
// 初始化Hashtable
Map ht = new Hashtable();
// 使用put方法插入元素
ht.put(1, "Geeks");
ht.put(2, "For");
ht.put(3, "Geeks");
ht.put(4, "For");
// 初始HashMap
System.out.println("Initial map : " + ht);
// 删除键为4的Map条目
ht.remove(4);
// 最终的Hashtable
System.out.println("Updated map : " + ht);
}
}
输出
Initial map : {4=For, 3=Geeks, 2=For, 1=Geeks}
Updated map : {3=Geeks, 2=For, 1=Geeks}
4. 遍历Hashtable: 我们可以使用高级for循环对表进行迭代。以下是迭代Hashtable的示例。
//迭代Hashtable的Java程序
import java.util.*;
class IteratingHashtable {
public static void main(String[] args)
{
// 初始化Hashtable
Hashtable ht = new Hashtable();
// 使用put方法插入元素
ht.put(1, "Geeks");
ht.put(2, "For");
ht.put(3, "Geeks");
// 使用for-each循环迭代Hashtable
for (Map.Entry e : ht.entrySet())
System.out.println(e.getKey() + " "
+ e.getValue());
}
}
// Java程序演示
// 遍历Hashtable
import java.util.Hashtable;
import java.util.Map;
public class IteratingHashtable {
public static void main(String[] args)
{
// 创建Hashtable实例
Hashtable<String, Integer> ht = new Hashtable<>();
// 使用put方法添加元素
ht.put("vishal", 10);
ht.put("sachin", 30);
ht.put("vaibhav", 20);
// 使用增强型for循环遍历
for (Map.Entry<String, Integer> e : ht.entrySet())
System.out.println(e.getKey() + " "
+ e.getValue());
}
}
输出:
vaibhav 20
vishal 10
sachin 30
Hashtable的内部工作原理
Hashtable数据结构是一个存储键/值对的bucket数组。它使用 hashCode()方法 确定哪个bucket应该映射键/值对。
哈希函数帮助确定存储桶中给定键的位置。通常,哈希码是非负整数,对于相等的对象相等并且可能对于不相等的对象不相等。为确定两个对象是否相等,Hashtable使用equals()方法。
可能两个不相等的对象具有相同的哈希码。这称为 冲突 。为解决冲突,Hashtable使用列表数组。映射到单个bucket(数组索引)的键值对存储在列表中,并将列表引用存储在数组索引中。

Hashtable的方法
- K – 映射中键的类型。
- V – 映射中值的类型。
返回此映射中包含的值的集合视图。
在接口java.util.Map中声明的方法
| 方法 | 描述 |
|---|---|
| forEach(BiConsumer<? super K, ? super V> action) | 对此映射中的每个条目执行给定的操作,直到处理完所有条目或操作抛出异常。 |
| getOrDefault(Object key, V defaultValue) | 如果此映射不包含键的映射,则返回将指定键映射到的值;否则返回默认值。 |
| putIfAbsent(K key, V value) | 如果指定的键尚未与值相关联(或映射到null),则将其与给定值关联,并返回null;否则返回当前值。 |
| remove(Object key,Object value) | 仅当指定的键当前映射到指定值时,才删除该键的条目。 |
| replace(K key, V value) | 仅当指定的键当前映射到某个值时,才替换该键的条目。 |
| replace(K key, V oldValue, V newValue) | 仅当当前映射到指定值时,才替换指定键的条目。 |
| replaceAll(BiFunction<? super K, ? super V, ? extends V> function) | 用调用该条目上的给定函数的结果替换每个条目的值,直到处理完所有条目或该函数引发异常。 |
极客教程