【问题标题】:How come my HashMap have a duplicate key?为什么我的 HashMap 有一个重复的键?
【发布时间】:2015-01-22 03:08:49
【问题描述】:

我们有一个名为 Subscriber 的类,它扩展了“HashMap”。我们在一个列表中有许多此类的实例,每个实例都有一组设置到地图的条目,其中一个是“状态”。

我们的程序正在通过调用订阅服务器上的一个方法来更新“状态”值,该方法对 HashMap 进行简单的放置。

我们的程序可以运行数天(数周)而没有任何问题,但有时我们会在系统的其他一些部分看到奇怪的行为,这些部分使用来自 HashMap 的数据。对我们来说,一个或多个订阅者实例中似乎存在重复键。

我们设法创建了一个 jmap 转储,并且基于该转储,当我在 VisualVM 中查看转储时,它会查找我们设置了两次“状态”。

我们目前正在运行 Java 版本:1.7.0_25 (Oracle)

这怎么可能?还是我看错了 VisualVM?

【问题讨论】:

  • 你是从多个线程写入地图吗?
  • HashMap 不是线程安全的。谷歌了解更多详细信息,您需要从一个线程访问它,或者使用 ConcurrentHashMap 代替。无论如何,从 HashMap 继承是一个非常值得怀疑的做法。
  • @user3074713:众所周知,线程问题很难重现。但从根本上说,如果你在多个线程中使用一个类,而它说不这样做,你至少不能排除这是问题的原因。考虑使用线程安全映射实现添加锁定。
  • 同意扩展HashMap的做法。此类旨在有效地将键映射到值。除非这也是订阅者类的主要目的,否则扩展 HashMap 表明设计不佳。请记住,extends 表示“is-a”关系;除非说“Subscriber is a HashMap”有意义,否则它可能是错误的设计。我怀疑“Subscriber has a HashMap”更合适。

标签: java hashmap hashcode visualvm jmap


【解决方案1】:

除了线程问题之外,还有一个明确的途径来获得这个结果:

class Key implements CharSequence {

    private byte[] key;

    public Key(String key) {
        // Take a copy of the bytes of the string.
        this.key = key.getBytes();
    }

    @Override
    public int length() {
        return key.length;
    }

    @Override
    public char charAt(int index) {
        return (char) key[index];
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        return new Key(new String(key).substring(start, end));
    }

    // Allow the key to change.
    public void setKey(String newValue) {
        key = newValue.getBytes();
    }

    @Override
    public String toString() {
        return new String(key);
    }
}

public void test() {
    Map<CharSequence, String> testMap = new HashMap<>();
    Key aKey = new Key("a");
    Key bKey = new Key("b");
    testMap.put(aKey, "a");
    testMap.put(bKey, "b");
    bKey.setKey("a");
    System.out.println(testMap.keySet());
}

这实质上是使地图的键可变,以便在将它们添加到地图后更改它们。

虽然这可能不是您面临的问题(多线程问题更有可能),但这是对问题的真正答案我的 HashMap 怎么会有重复键?

【讨论】:

  • 这是对问题标题的回答。在屏幕截图中,可以看到键是一个字符串,所以它不是完整问题的答案;-)
  • 除了截图清楚地显示key的类型是String。
猜你喜欢
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 2017-07-11
  • 2015-12-28
  • 2017-07-06
  • 2014-05-21
  • 2016-06-19
  • 1970-01-01
相关资源
最近更新 更多