当前位置: 首页 > 知识库问答 >
问题:

Java散列表的关键字不在散列表中

岑叶秋
2023-03-14

我正在用java编写一个小程序,根据netflow数据为防火墙创建访问列表。

简而言之,我有一个名为< code > sourceAggregatedFlows 的hashmap,它包含作为键的源IP组(自定义对象)和作为值的目的IP地址

private static Map<List<IPGroups>, String> sourceAggregatedFlows = new HashMap<List<IPGroups>, String>();

在我的代码中,我需要迭代源IP组,并确定键值中的目标地址是否与我搜索的地址匹配。

我注意到一个问题,有时遍历键集会在值上产生一个nullpointer异常。我已经开始调试并发现,这段代码:

if (sourceAggregatedFlows.containsValue(destination)) {
    for (List<IPGroups> sources : sourceAggregatedFlows.keySet()) {
        System.out.println(sourceAggregatedFlows.containsKey(sources));
    }
}

不知何故可以打印出来:

false
true
true

查看调试器,一切似乎都很好。hashmap包含3个非空键和3个非空值

此时,目标变量(字符串)的值与哈希映射中的第一个值相同。我也用调试器工具检查了它,它的source变量似乎与哈希图中的第一个键完全匹配,但由于某种原因,它仍然在最后输出为false。

这对我来说似乎是一个不可能的场景,因为我还没有在单线程程序中经历过这样的事情。

可能是我的编程技能有点生锈,但我不知道wat会导致这种情况,但它甚至不会一直发生。它总是发生在我的程序中的同一点,当目标变量和哈希图的第一个值为“172.24.22.54”时。在此之前,它会按预期执行两次(在同一次运行中)。

有没有人有过这样的事情的经验?这可能是Java的错误版本,还是我错过了什么?

共有2个答案

齐才艺
2023-03-14

在地图中不能使用不稳定的对象作为键。当你使用非稳定时,你会得到这种确切的行为:可以用迭代器“观察”到的键,但用< code >根本观察不到。包含键,< code >。获取,< code >。computeifavent ,或任何其他“精确定位”方法。

非稳定对象是指在将其添加到映射中后hashCode发生变化的对象。这可能是因为hashCode天生不稳定(这使得它完全无用,意味着您的hashCode impl只是坏了;修复它),或者因为对象是可变的,然后您对它进行了变异。

最后一点是99%确定这里发生了什么。你做了这个:

  • 列出一个清单。
  • 将其作为键添加到地图中。
  • 在列表中添加或删除内容。

你不能这样。没有简单的解决办法。一个解决方案是:

  • 任何时候你想改变列表…
  • 在变异之前,从图中删除k/v对
  • 使其变异
  • 把它加回来

另一种方法是简单地不使用您想要变异的东西作为密钥;相反,使用其他稳定的键,然后有2个映射。一个将稳定键映射到您的List

原因很简单:

Hashmap的工作方式如下:为了存储任何东西,它获取键并请求它的hashCode。然后,它为该hashcode找到正确的“桶”,并将密钥放入该桶中。

要查找键,例如执行 map.get(k),哈希映射会询问“k”以获取其哈希代码,然后仅在该存储桶中查找,而不在其他存储桶中查找。

因此,如果您在对象具有哈希代码1234时将其放入bucket 1200-1300中。如果稍后同一对象的hashcode()现在返回4321,您将调用map。get(k),hashmap在bucket 4300-4400中查找,但找不到它,并返回:不,它不在这里!

燕翔飞
2023-03-14

我相信您遇到的问题是因为您的HashMap密钥(即列表)不是不可变的。

如果您先进行散列,然后更改密钥,则不一定能够找到值

 类似资料:
  • 考虑 HashSet 作为一个 HashMap,在此处我们只关心键(HashSet<T> 实际上只是一个包围 HashMap<T, ()> 的装包(wrapper))。(原文:Consider a HashSet as a HashMap where we just care about the keys (HashSet<T> is, in actuality, just a wrapper a

  • 执行更新的操作是: 当有多个实例时,我出现在竞争条件下。有没有一种方法以原子的方式更新列表值?

  • 任何实现了 Eq 和 Hash trait 的类型都可以充当 HashMap 的键。这包括: bool (当然这个用处不大,因为只有两个可能的键) int,unit,以及所有这类型的变量 String 和 &str(友情提示:可以创建一个由 String 构成键的 HashMap,并以一个 &str 来调用 .get())(原文:String and &str (protip: you can h

  • 为什么他们不一样?我需要如何更改java版本以使其与Go版本完全相同?

  • 根据关键码值(Key value)直接进行访问的数据结构;它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度;这个映射函数叫做散列函数,存放记录的数组叫做散列表。

  • 主要内容:哈希表的构建,哈希函数的构造,处理冲突的方法,总结前面介绍了静态 查找表以及动态查找表中的一些查找方法,其查找的过程都无法避免同查找表中的数据进行比较,查找算法的效率很大程度取决于同表中数据的查找次数。 而本节所介绍的 哈希表可以通过关键字直接找到数据的存储位置,不需要进行任何的比较,其查找的效率相较于前面所介绍的查找算法是更高的。 哈希表的构建 在初中的数学课本中学习过函数的相关知识,给定一个 x,通过一个数学公式,只需要将 x 的值带入公式就