【问题标题】:Bug in HashMap / ArrayList or wrong code? [duplicate]HashMap / ArrayList 中的错误或错误代码? [复制]
【发布时间】:2016-10-09 03:25:21
【问题描述】:

厌倦了尝试使用此代码解决问题:

public class MapTest {
    static class T{
        static class K{}
    }
    static Map<List<T.K>, List<String>> map = new HashMap<>();
    static List<String> test(List<T.K> list, String s){
        List<String> l = map.get(list);
        if (l == null){
            l = new ArrayList<String>();
            System.out.println("New value()");
            map.put(list, l);
        }
        l.add(s);
        return l;       
    }
    public static void main(String s[]){        
        ArrayList<T.K> list = new ArrayList<T.K>();
        test(list, "TEST");
        list.add(new T.K());
        List<String> l = test(list, "TEST1");
        System.out.println(l.size());
    }
}

它应该只为地图创建一个新的列表值,但输出如下:

New value
New value
1

我在其中插入值后,列表的哈希码发生了错误。 我希望“新值”只出现一次,大小为 2,而不是 1。 它只是JVM问题还是更普遍的问题? 我的一个是 Oracle JVM 1.8.0_65

【问题讨论】:

  • 这个例子说明了为什么使用可变类型和 Map 键是一个坏主意。 list.add(new T.K()); 导致列表生成不同的哈希码,因为它不再为空,因此地图无法再找到现有实例。顺便说一句:List#hashCode 的 JavaDoc 很好地解释了它的行为。
  • 一般来说:java标准库没有bug。如果他们有错误,他们是非常微妙的。含义:可以非常自信地假设图书馆是正确的;而那些想法/假设......不是。
  • @Jägermeister,这有点强。我个人在 Java 标准库中发现了错误,这已被接受的错误报告所证实。还有很多很多其他人报告的错误。尽管如此,你是对的,一个人的一般姿态应该是观察到的任何不当行为几乎可以肯定是因为自己的代码不好,而不是因为标准库有错误。
  • @ManoDestra toString 对地图并不重要。
  • 抱歉,我的意思是hashCode()。如果他希望返回引用,他可以使用System.identityHashCode(list)。但是,他不应该使用这种 IMO 密钥。 stackoverflow.com/questions/580984/…

标签: java dictionary hash


【解决方案1】:

当您将项目放入其中时,列表对象的哈希码会发生变化。您可以在ArrayList.hashCode 文档中查看哈希码是如何计算的。

一般来说,使用可变对象作为映射的键不会很好地工作。根据Map documentation

注意:如果将可变对象用作映射键,则必须非常小心。如果对象的值以影响等于比较的方式更改,而对象是映射中的键,则不会指定映射的行为。

因此,当您第二次将列表添加到地图时,地图不会将其视为与第一个列表“相等”(因为它不符合 .equals),所以它再次添加它.

【讨论】:

  • 我实际上并不清楚按项目计算哈希背后的想法,但是好的,谢谢。我今天真的很累;)
  • @Павел 如果您不考虑 List1 和 List2 的项目,您会有什么不同?
  • @Tom,我在想equals独立于hashCodes进行比较,hash就像往常一样Object.hashCode。我知道我错了,以后会更加小心。坏事我已经重构了我的代码,然后 Joni 提到 IdentityHashMap 存在。我通常使用对象或字符串作为键,因为它更自然。但是这次我需要存储字符串不唯一的列表和字符串对,所以我交换了键和值。因为我只需要顺序访问,所以它不会影响性能。但是逻辑被打破了,因为我没有使用 IdentityHashMap,而我需要。
【解决方案2】:

如果您想要一个按标识而不是按值查找键的映射,您可以使用IdentityHashMap 类。

【讨论】:

  • 请注意,谢谢
猜你喜欢
  • 2011-01-03
  • 2016-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-05
  • 2018-08-24
  • 1970-01-01
  • 2020-04-24
相关资源
最近更新 更多