Java中的map.containsKey方法无法正常工作

4

这个问题看起来很简单,但我已经试了几个小时(不需要实现hashCode比较)让containsKey方法正常工作。为了简化问题,我将发布一个简单的代码示例,我在其中遇到了问题:

public class myPair {
private int a;
private int b;

    myPair(int x, int y) {
        a=x;
        b=y;
    }

    public boolean equals(Object pair) {
        System.out.println("Ola");
        return true;
    }   


    int first()  { return a; }
    int second() { return b; }

    public String toString() {
        return "X: "+this.a + " Y:"+this.b; 
}
}

public class Main {
    public static void main(String args[]){
        Map<myPair,String> myMap = new LinkedHashMap<myPair, String>();
        myMap.put(new myPair(2, 2), "encontrou me");
        if(myMap.containsKey(new myPair(2, 2))){
            System.out.println(myMap.get(new myPair(2, 2)));
        }
        System.out.println(myMap.get(new myPair(2,2)));
    }
}

这将输出:
null

我已经实现了equals方法......为什么它没有起作用呢?


4个回答

11
由于使用HashMap(或LinkedHashMap),您必须覆盖hashCode方法。这就是哈希图的工作原理:它们首先计算哈希码以大致确定查找对象的位置。如果哈希码与目标对象的哈希码不相等,则它将在错误的位置查找对象!
这来自Object.hashCode的API文档:
如果两个对象根据equals(Object)方法是相等的,则在两个对象上调用hashCode方法必须产生相同的整数结果。
hashCode的默认实现很多次并不会为两个不同的对象返回相同的哈希码。
基本上,通过覆盖equals但未覆盖hashCode,您正在违反API的契约。

有没有办法在不使用它的情况下使用地图结构?我该如何实现它? - out_sider
2
你可以尝试使用另一种映射实现,比如TreeMap(但是你的键需要是可比较的)。然而,如果你重写了equals方法,而没有同时重写hashCode方法,那么你就违反了API的契约。 - aioobe
好的,我会尝试实现hasCode成员...谢谢...我该如何将这个问题标记为已解决呢? - out_sider

1

你还需要按照aioobehvgotcodes的解释重写hashCode方法。
由于equals方法总是返回true,所以hashCode方法必须始终返回相同的值:

    @Override
    public int hashCode() {
        return 123;    // qualquer número (any other number)
    }

但是我怀疑一个带有equals方法并始终返回true的对象并不是非常有用的。至少不适用于作为映射中的键:由于没有不同的键,因此在映射中无法拥有多个键值对。(可能对测试有用)


0
你需要一个hashCode方法,而且你的equals方法总是返回true,这是不正确的。

-4

你可以从 Khalid Mughal 和 Rolf W Rasmussen 的优秀书籍中学习这些概念。它被称为 SCJP。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接