为什么在哈希映射中使用空值或空键是有用的?

Hashtable不允许使用null键或值,而HashMap允许使用空值和1个null键。

问题:

  1. 为什么会这样?
  2. 在HashMap中使用这样的键和值有什么用?

1.为什么会这样?

HashMap比Hashtable更新并修复了它的一些限制。

我只能猜测设计师在想什么,但这是我的猜测:

  • Hashtable通过在每个键上调用hashCode来计算每个键的哈希值。 如果密钥为空,这将失败,因此这可能是禁止空值作为键的原因。
  • 如果密钥不存在,方法Hashtable.get将返回null。 如果null是一个有效值,那么null是否意味着密钥存在但值为null,或者密钥是否不存在则不明确。 歧义是不好的,所以这可能是禁止空值作为值的原因。

然而事实certificate,有时你确实想要存储空值,因此在HashMap中删除了限制。 HashMap.get的文档中还包含以下警告:

返回值null不一定表示映射不包含键的映射; 地图也可能将键显式映射为null。


2.在HashMap中使用这样的键和值有什么用?

显式存储null以区分您知道存在但没有关联值的键和不存在的键很有用。 一个例子是注册用户及其生日的列表。 如果您要求特定用户的生日,您希望能够区分不存在的用户和现有用户,但他们尚未进入他们的生日。

我想不出任何(好的)理由想要将null存储为键,并且通常我建议不要使用null作为键,但是可能至少有一个人需要那些键可以是空值。

好吧,我认为Mark Byers完美回答,所以只是一个简单的例子,其中空值和键可能有用:

想象一下,你有一个昂贵的函数,它总是为相同的输入返回相同的结果。 地图是缓存其结果的简单方法。 也许有时函数会返回null,但无论如何你都需要保存它,因为执行起来很昂贵。 因此,必须存储空值。 如果它是函数的可接受输入,则同样适用于null键。

JDK 1.0开始 ,HashTable是非常老的类。从JDK 1.0到位的类称为Legacy类,默认情况下它们是同步的

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

HashTable类是在散列机制上实现的,意味着存储任何键值对,其所需的键对象哈希码。 HashTable通过在每个键上调用hashCode来计算每个键的哈希值。 这将失败如果key为null,它将无法为null键提供散列,它将抛出NullPointerException ,类似于value的情况,如果值为null则抛出null

但后来人们意识到null键和值有其自身的重要性,然后引入了HashTable的修改实现,就像HashMap一样,允许一个空键和多个空值。

对于HashMap,它允许一个空键并且对键进行空检查,如果键为null,则该元素将存储在Entry数组中的零位置。

我们在HashMap中不能有多个Null键,因为Keys是唯一的,因此只允许一个Null键和许多Null值。

USE – 我们可以使用Null键作为某些默认值。

后来,作为ConcurrentHashMap引入了HashTable的修改和更好的实现。

除了Mark Ba​​yers所回答的问题之外,Null被视为数据,必须将其存储为值以便进一步检查。 在许多情况下,null as value可用于检查密钥条目是否存在但没有为其分配值,因此可以采取相应的操作。 这可以通过首先检查密钥是否存在,然后获取值来完成。 还有一个案例就是放入任何数据(没有任何检查)。 获得后,所有检查都会应用到它。

虽然null作为键,但我认为可以用来定义一些默认数据。 通常为null作为键是没有多大意义的。

HashMap爵士也在内部使用hashCode()方法在HashMap中插入一个元素,所以我认为这不是“为什么HashTable允许空键”的正当理由

它将使Map界面更容易使用/更简洁。 null是引用类型的合法值。 使映射能够处理空键和值将消除在调用api之前进行空值检查的需要。 因此,map api在运行时创建的“惊喜”更少。

例如,通常使用map来基于单个字段对同类对象的集合进行分类。 当map与null兼容时,代码将更简洁,因为它只是一个没有任何if语句的简单循环(当然你需要确保集合没有null元素)。 没有分支/exception处理的更少代码行更可能在逻辑上正确。

另一方面,不允许null不会使地图界面更好/更安全/更容易使用。 依赖于地图来拒绝空值是不切实际的 – 这意味着将抛出exception并且您必须捕获并处理它。 或者,为了摆脱exception,你必须确保在调用map方法之前没有任何东西 – 在这种情况下你不关心map是否接受null,因为你无论如何都要过滤输入。