创建可用作hashmap键的Java类

时间:2014-12-20 19:26:57

标签: java hashmap

我创建了一个名为Coordinates的类,它只包含一些xy个整数。我想将其用作HashMap的密钥。

但是,我注意到当您创建具有相同Coordinatesx值的y的两个不同实例时,它们将被哈希映射用作不同的键。也就是说,即使两个条目具有相同的坐标,也可以输入两个条目。

我已覆盖equals()

public boolean equals(Object obj) {
    if (!(obj instanceof Coord)) {
        return false;
    }else if (obj == this) {
        return true;
    }
    Coord other = (Coord)obj;
    return (x == other.x && y == other.y);
}

但是HashMap仍然使用这两个实例,就像它们是不同的键一样。我该怎么办?

我知道我可以使用两个元素的整数数组。但我想用这个课。

4 个答案:

答案 0 :(得分:6)

您需要覆盖hashCode。 Java 7为此提供了一种实用方法。

@Override
public int hashCode() {
    return Objects.hash(x, y);
}

答案 1 :(得分:4)

您还应该覆盖hashCode(),以便两个相等的实例具有相同的hashCode()。 E.g:

@Override
public int hashCode() {
    int result = x;
    result = 31 * result + y;
    return result;
}

请注意,对于两个不等于具有不同哈希码的实例,并不是严格要求,但是您拥有的冲突越少,您从HashMap获得的性能就越好。

答案 2 :(得分:1)

哈希映射使用hashCode对象方法来确定将对象放入哪个存储桶。 如果您的对象未实现hashCode,则它会继承Object的默认实现。来自docs

  

尽可能合理,Object类定义的hashCode方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但JavaTM编程语言不需要此实现技术。)

因此,每个对象看起来都是不同的。

请注意,不同的对象可能会返回相同的hashCode。 这称为碰撞。 当发生这种情况时 然后除hashCode之外, 哈希映射实现将使用equals方法来确定两个对象是否相等。

请注意,大多数IDE都提供从您的类中定义的字段生成equalshashCode方法。事实上,IntelliJ鼓励同时定义这两种方法。有充分的理由。这两种方法密切相关, 每当你更改其中一个,或实现其中一个,或覆盖其中一个, 你必须审查(并且最有可能改变)另一个。

此类中的方法是100%生成的代码(通过IntelliJ):

class Coord {
    private int x;
    private int y;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Coord coord = (Coord) o;

        if (x != coord.x) return false;
        if (y != coord.y) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }
}

答案 3 :(得分:0)

您可能没有覆盖hashCode方法。为什么需要这个?要回答这个问题,您必须了解散列表的工作原理。

哈希表基本上是一个链表列表。数组中的每个桶对应于hashCode % numberOfBuckets的特定值。具有相同hashCode % numberOfBuckets的所有对象将存储在关联存储桶中的链接列表中,并且将基于其equals方法识别(在查找期间)。因此,确切的规范是a.hashCode() != b.hashCode() => !a.equals(b),相当于a.equals(b) => a.hashCode() == b.hashCode()

如果使用基于引用的hashCode的默认实现,那么两个相等但具有不同引用的对象(因此,很可能是不同的hashCode)将存储在不同的桶,导致重复的密钥。