为什么Hashtable不允许空键或值?

正如JDK文档中所指定的,Hashtable不允许使用null键或值。 HashMap允许一个空键和任意数量的空值。 为什么是这样?

Hashtable是较旧的类,通常不鼓励使用它。 也许他们认为需要一个null键,更重要的是 – null值,并将其添加到HashMap实现中。

HashMap更新,并且具有更高级的function,这基本上只是对Hashtablefunction的改进。 创建HashMap时,它专门设计为将空值作为键处理并将其作为特殊情况处理。

编辑

Hashtable JavaDoc :

要从Hashtable成功存储和检索对象,用作键的对象必须实现hashCode方法和equals方法。

由于null不是对象,因此不能在其上调用.equals().hashCode() ,因此Hashtable无法计算哈希值以将其用作键。

原因是接受答案的原因:Hashtable是旧的。

但是,在每种情况下都不鼓励使用Hashtable支持HashMap。

  • Hashtable是同步的,所以它是THREAD-SAFE 。 HashMap不是。

Hashtable和ConcurrentHashMap都不支持null键或值。 HashMap有。

如果你想要一个替换,除了改变类并且在每个场景中都可以工作之外什么都不需要,那么就没有了。 最相似的选项是ConcurrentHashMap (它是线程安全的,但不支持锁定整个表):

在依赖于线程安全但不依赖于其同步细节的程序中,此类可与Hashtable完全互操作。

由于同步引入的性能影响,HashMap是单线程应用程序的更好替代品,或者不需要任何时间同步。

资料来源:

  • 哈希表
  • HashMap中
  • 的ConcurrentHashMap

总结一下

因为在放置元素的HashTable中,它会考虑键和值哈希。 基本上你会有类似的东西:

 public Object put(Object key, Object value){ key.hashCode(); //some code value.hashCode(); } 

HashTable – 不允许null键这是因为,在put(K key,V value)方法中,我们有key.hashcode(),它抛出空指针exception。 HashTable – 不允许空值这是因为,在put(K key,V value)方法中我们有if(value == null){throw new NullPointerException

HashMap允许空值,因为它没有像HashTable这样的任何检查,而它只允许一个空键。 这是在putForNullKey方法的帮助下完成的,每次将密钥提供为null时,该方法都会将值添加到内部数组的第0个索引

哈希表是非常古老的类,来自JDK 1.0

要理解这一点,首先我们需要理解作者在这个课上写的评论。 “这个类实现了一个哈希表,它将键映射到值。 任何非null对象都可以用作键或值。 要成功存储和检索哈希表中的对象,用作键的对象必须实现hashCode方法和equals方法。“

HashTable类是在散列机制上实现的,这意味着存储任何键值对,它是键对象的必需哈希码。 如果key为null,则无法给出散列,它将通过空指针exception和类似的值为值,如果值为null则抛出null。

但后来人们意识到null键和值有其自身的重要性,这就是为什么在后来实现的类(如HashMap类)中允许一个null键和多个null值的原因。

对于散列映射,空键将允许并且如果键为空则存在对于键的空检查,那么该元素将存储在Entry数组中的零位置。 null键我们可以使用一些默认值..

=> Hashtable方法是同步的,它永远不会使用基于对象的锁定。

HashMap通过考虑它特殊来实现

  static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } 

Java 8你无法推断哈希表的类型。

 private Map hashtable = new Hashtable<>(); // Not Allowed private Map hashtable = new HashMap<>(); // Allowed 

Hashtable和ConcurrentHashMap不允许空键或值的主要原因是期望它们将在multithreading环境中使用。 一分钟,让我们假设允许空值。 在这种情况下,get方法具有不明确的行为。 如果在映射中找不到键,则它可以返回null;如果找到键并且其值为null,则它可以返回null。 当代码需要空值时,它通常会检查映射中是否存在键,以便它可以知道密钥是否存在或密钥是否存在但值为null。 现在这个代码在multithreading环境中中断了。 我们来看看下面的代码:

 if (map.contains(key)) { return map.get(key); } else { throw new KeyNotFoundException; } 

在上面的代码中,假设线程t1调用contains方法并找到密钥,它假定密钥存在并准备好返回值,无论它是否为null。 在调用map.get之前,另一个线程t2从地图中删除该键。 现在t1恢复并返回null。 但是根据代码,t1的正确答案是KeyNotFoundException,因为密钥已被删除。 但它仍然返回null,因此预期的行为被打破。

现在,对于常规的HashMap,假设它将被单个线程调用,因此在“包含”检查和“获取”的中间不可能删除密钥。 因此HashMap可以容忍空值。 但是对于Hashtable和ConcurrentHashMap,期望很明显,多个线程将对数据进行操作。 因此,他们不能允许空值并给出错误的答案。 键的逻辑也是一样的。 现在,counter参数可以是 – 对于Hashtables和ConcurrentHashMaps的非空值,contains和get步骤可能会失败,因为另一个线程可以在执行第二步之前修改map / table。 这是正确的,它可能发生。 但由于Hashtables和ConcurrentHashMaps不允许使用null键和值,因此它们不必首先实现contains和get check。 他们可以直接获取值,因为他们知道如果get方法返回null,唯一的原因是键不存在而不是因为值可能为null。 只有HashMaps才需要包含和获取检查,因为它们允许空值,因此需要解决关于是否找不到键或值为空的歧义。

HashTable – 不允许空键
这是因为,在put(K key,V value)方法中,我们有key.hashcode() ,它抛出空指针exception。
HashTable – 不允许空值
这是因为,在put(K key,V value)方法中我们有if(value==null){throw new NullPointerException

HashMap允许空值,因为它没有像HashTable这样的任何检查,而它只允许一个空键。 这是在putForNullKey方法的帮助下完成的,每次将密钥提供为null时,该方法都会将值添加到内部数组的第0个索引