【问题标题】:Java HashMap, hashCode() equals() - how to be consistent with multiple keys? [duplicate]Java HashMap, hashCode() equals() - 如何与多个键保持一致? [复制]
【发布时间】:2015-08-22 12:19:40
【问题描述】:

我有一个 ID 类。它指的是对一个独特的人的识别。身份证有两种形式。用户名和用户号。如果用户名匹配或用户编号匹配,则 ID 指的是同一个人。我想使用 ID 类作为哈希图中的键来查找人员。我重写了 equals 方法,以明确如果两个 ID 相等,则表示它们指的是同一个人。我假设我需要重写 hashCode() 方法,因为我想要 的哈希图。但我不知道怎么做。如何使 ID 类成为我的 HashMap 可接受的键?

public final class ID {

    // These are all unique values. No 2 people can have the same username or id value.
    final String username_;
    final long idNumber_;

    public ID(String username, Byte[] MACaddress, long idNumber) {
    username_ = username;
    idNumber_ = idNumber;
    }

    /**
     * Checks to see if the values match. 
     * If either username or idNumber matches, then both ID's refer to the same person.
     */
    public boolean equals(Object o) {
    if (!(o instanceof ID)) {
        return false;
    }
    ID other = (ID) o;
    if (this.username_ != null && other.username_ != null) {
        if (this.username_.equals(other.username_)) {
            return true;
        }
    }
    if (this.idNumber_ > 0 && other.idNumber_ > 0) {
        if(this.idNumber_ == other.idNumber_) {
            return true;
        }
    }
    return false;
    }
}

跟进:如果我想为唯一的社会安全号码添加第三个字段怎么办?这将如何改变我的人员查找哈希图和 ID 类?

请注意,hashCode 的维基百科页面显示:

The general contract for overridden implementations of this method is that they behave in a way consistent with the same object's equals() method: that a given object must consistently report the same hash value (unless it is changed so that the new version is no longer considered "equal" to the old), and that two objects which equals() says are equal must report the same hash value.

更新

迄今为止最好的解决方案: 为每个不可变的唯一标识符制作一个单独的 HashMap,然后将所有 HashMap 包装在一个包装器对象中。

【问题讨论】:

  • 您是说,您将在地图中输入一个作为 ID 号的键,然后通过提供一个只是名称的 ID 来查找它?或者如果你输入一个数字 id,你将永远有一个数字 id,反之亦然?
  • @Jayan - 我怀疑这是重复的。 OP 没有询问合同细节/陷阱。就是如何根据他的要求设计它。
  • @prabugp >> 你是说,你会在地图中放一个作为 ID 号的键,然后通过提供一个只是名称的 ID 来查找它? -- 不。如果你查看了 equals 方法是如何实现的,要么 ID 必须匹配,要么名称必须匹配,或者两者都匹配,才能成为获取该 person 值的匹配键。这就像我创建了一个 ID,其中包含我的社会安全号码和我的姓名,然后我将它放在 HashMap 中,并带有一个引用我的值。然后有人创建了一个只是我的名字的新 ID,他们把它放在 hashmap 中,它返回给我。如果只是我的号码,也一样。
  • 或者也许我改了名字但我的号码还是一样。然后有我的旧名字和号码的人仍然可以在哈希图中查找我,因为即使我的名字不匹配,我的号码也是匹配的。这有意义吗?

标签: java hash hashmap key


【解决方案1】:

我认为您的问题确实远远超出了 hashCode 的简单实现 - 它实际上是关于何时应将两个 ID 视为相等的设计。

如果您有多个字段所有都是唯一的,那么您实际上处于一个棘手的情况。忽略MAC地址部分,ID码本身没有什么可以停止的:

ID a = new ID("a", 0);
ID b = new ID("b", 0);
ID c = new ID("a", 1);

现在根据您的规则,这三个 ID 不应该都能够共存 - 因为它们在某种程度上都是平等的。 (ab 同名,ac 同号。)

此外,看起来数字和名称实际上都是可选的 - 根据我的经验,这最终可能会很痛苦。

可能让你的类保持原样仍然有意义,但是围绕“没有两个实体可以有相同的名字”和“没有两个实体可以有相同的数字”的规则是' t 实际上与“没有两个实体可以具有相同的 ID”相同,因此您必须单独执行。

您完全有可能希望为“按名称的实体”保留HashMap<String, Entity>,为“按编号的实体”保留HashMap<Integer, Entity>。然后我将在ID 中实现equalshashCode 以检查complete 相等性 - 这样在仅通过ID 的one 部分查找ID 之后,您可以检查您找到的 ID 是否正确。

或者,将您的身份方案更改为只有一个部分,这样您就不必担心这一点。即使您有某种“辅助标识符”,也值得决定将其中的 一个 作为您通常用于查找实体、存储它们等的主要标识符 - 然后您只需在主要和次要标识符之间有一个次要映射(无论是在内存中还是在数据库中等)。如果您所有的“真实”标识符都是可选的,您甚至可能希望有一个 保证 存在的代理标识符,然后该标识符与辅助标识符之间的所有映射都是可选的。 (它们甚至可能是可变的 - 例如,您可以稍后针对现有实体“发现”并记录社会安全号码。)

【讨论】:

  • >> 此外,看起来数字和名称实际上都是可选的——根据我的经验,这最终可能会很痛苦。 ——是的,这就是我想要的。如果有人知道我的姓名或电话号码,他们应该能够找到我。
  • @Sacha:那么他们没有身份证,他们有名字或号码。
  • >> 如果您有多个字段都是唯一的,那么您实际上处于一个棘手的情况。 -- 如果需要,我可以添加一个非唯一字段。诸如“年龄”之类的东西对于给定的人来说是非唯一的,如果这会让事情变得更容易的话。
  • >> 那么他们没有身份证,他们有名字或号码。 - 对不起。如果您愿意,可以将其称为查找键。
  • 如果真的很糟糕,我可以用另一个数据结构替换 HashMap。可以让我快速通过姓名或 ID 查找一个人,并且允许我同时提供姓名和 ID 并且即使其中一个字段发生更改仍能获得匹配项。
猜你喜欢
  • 2010-09-29
  • 1970-01-01
  • 1970-01-01
  • 2016-05-23
  • 1970-01-01
  • 2011-12-03
  • 1970-01-01
  • 1970-01-01
  • 2013-02-17
相关资源
最近更新 更多