【问题标题】:In which cases will a hashmap in java lose some entries? [closed]在什么情况下,java 中的 hashmap 会丢失一些条目? [关闭]
【发布时间】:2012-12-30 07:51:26
【问题描述】:

我写了一个哈希图并用键/值条目填充它。值是对象。该地图包含至少 10,000 个条目。稍后当我想使用某个键获取值时,地图似乎找不到这个条目。这太奇怪了。即使每次它在不同的条目上失败。我能做些什么来解决这个问题?我正在使用 weblogic 作为服务器。我应该使用任何环境值吗?

【问题讨论】:

  • 您应该使用调试器来调试您的代码。 (我不确定您还期待什么其他答案!)

标签: java hashmap weblogic key-value


【解决方案1】:

以下是一些可能导致条目“丢失”的情况:

  • 在您的关键对象上错误地实现了 equals / hashcode 方法。这两种方法需要遵守“契约”才能使哈希表正常工作。最重要的属性是:

    key1.equals(key2) IMPLIES key1.hashcode() == key2.hashcode
    
  • 在地图中使用密钥时更改的可变密钥对象。特别是,如果 key 改变导致 key 的 hashcode 改变,它就会丢失。 (在这种情况下,如果您遍历整个地图,条目将显示出来。但是使用 has lookup 的地图操作不会找到它们......因为它们位于错误的哈希链上。)

    最安全的方法是使用不可变的密钥类。

  • 在没有正确同步的多线程应用程序中使用映射。这可能会导致地图数据结构损坏,表现为条目丢失。

  • 您不知道的应用程序的其他部分正在删除条目。


声明/声明您必须覆盖equalshashcode 的答案不正确。在某些情况下,这些方法的 Object 实现正是需要的。您必须做的是确保:

  1. 您正在使用您的用例要求的适当形式的密钥相等,并且
  2. 您的equalshashcode 符合“合同”。

我可以做些什么来解决这个问题?

我建议进行代码检查以检查上述问题。

调试是另一种选择。例如,您可以查看是否可以在错误的哈希链上找到丢失的条目。但是,我怀疑这种方法可能有点“碰巧”。

我正在使用 weblogic 作为服务器。

不相关...除非您碰巧使用由 Weblogic 而不是 J2SE 实现的某些 Map 实现类。 (查看对象的类名。)

我应该使用任何环境值吗?

没有。没用的

【讨论】:

    【解决方案2】:

    一种可能的情况是:

    如果 key 是类的实例并且该类没有覆盖 equals/hashcode 方法,则 get 方法可能返回 false。

    【讨论】:

    • 哈希映射实现应该优雅地处理哈希冲突。无论如何,hashCodeequalsObject 实现应该做正确的事情。所以这种情况只有在类实现了 broken equals 覆盖时才成立。
    • 哦,我明白你的意思了。在我之前的评论中,我只考虑使用 very same 键实例执行查找的情况。
    【解决方案3】:

    如果您的 Key 是可变的,那么以改变其哈希值的方式改变 Key 将导致查找失败。

    例如,假设您有以下可变类:

    public class MyKey {
        private int value;
        public void setValue(int value) {
            this.value = value;
        }
        public int hashCode() {
            return value;
        }
        public boolean equals(Object obj) {
            //...
        }
    }
    

    那么这是可能的:

    MyKey key = new MyKey();
    key.setValue(1);
    
    Map<MyKey, String> map = new HashMap<MyKey, String>();
    map.put(key, "Hello");
    
    System.out.println("map contains: " + map.get(key)); // "map contains: Hello"
    key.setValue(2);
    System.out.println("map contains: " + map.get(key)); // "map contains: "
    

    【讨论】:

    • 谢谢!我正是这样做的,因为我需要键中所有可能的值组合的值。这个答案救了我。对于任何想要做同样事情的人,而不是使用相同的键并设置他的值,我最终创建了 .使用构建器的不同关键对象。因此,从通用构建器开始,设置值并在放入地图时执行 builder.build()。
    【解决方案4】:

    扩展 Nambari 的答案:

    如果您使用不覆盖equals 和hashCode 作为键的类,则相等性基于对象相等性(例如:相同的对象地址,不同的内容)。这与您不能将字符串与 == 进行比较的原因相同。

        class Key {
           public String k;
           public Key(String k) { this.k = k; }
    
           /*
           //with this it would work.
           public boolean equals(Object o) { 
                if (o instanceof Key) return ((Key)o).k.equals(k);
                return false;
           }
    
           public int hashCode() {
                return k.hashCode();
           }
           */
        }
    
        map.put(new Key("a"),"test");
        map.get(new Key("a"));  // does NOT return "test" because key is another instance.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      • 2020-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多