【问题标题】:Java HashMap with overridden hashCode() and equals() returns no data具有覆盖 hashCode() 和 equals() 的 Java HashMap 不返回数据
【发布时间】:2010-11-24 17:44:36
【问题描述】:

我最近一直在使用 Java 的 HashMap,并且遇到了一些有趣的行为。我目前正在使用它来存储具有多个字段的键/值对象。为此,我重写了 hashCode() 和 equals(),如下所示:

public final class TransitionState {

private String mStackSymbol;
private String mTransitionSymbol;
private int mState;

private static final int HASH_SEED = 7;     //Should be prime
private static final int HASH_OFFSET = 31;

//Constructor and getter methods here

public boolean equals(TransitionState other) {

    //Check that we aren't comparing against ourself
    if (this == other) {
        return true;
    }

    //Check that we are not comparing against null
    if (other == null) {
        return false;
    }

    //Check fields match
    if ((mState == other.getState()) &&
        (mTransitionSymbol.equals(other.getTransitionSymbol())) &&
        (mStackSymbol.equals(other.getStackSymbol()))) {

        return true;

    } else {
        return false;

    }
}

public int hashCode() {
    int intHash = HASH_SEED;

    //Sum hash codes for individual fields for final hash code
    intHash = (intHash * HASH_OFFSET) + mState;
    intHash = (intHash * HASH_OFFSET) + (mTransitionSymbol == null ? 0 : mTransitionSymbol.hashCode());
    intHash = (intHash * HASH_OFFSET) + (mStackSymbol == null ? 0 : mStackSymbol.hashCode());

    return intHash;
}
}

现在,我可以毫无问题地将项目放入地图中。然而,检索它们是另一回事。每当我尝试从 HashMap 中获取()时,都会返回 NULL。我编写了一些测试代码来迭代 Map 并打印值,这就是事情变得令人困惑的地方,因为我的关键对象的 hashCode() 与我在我的地图中拥有的匹配并且与已知值的相等性返回 true。示例输出如下(参见表格底部的第四个转换):

Transition Table:
State  Symbol  Stack  Move
--------------------------
1, a, b, (1, pop) with key hashcode 212603 and value hashcode 117943
0, b, a, (0, pop) with key hashcode 211672 and value hashcode 117912
1, b, z, (1, push) with key hashcode 212658 and value hashcode 3459456
0, a, b, (0, pop) with key hashcode 211642 and value hashcode 117912
1, a, z, (0, push) with key hashcode 212627 and value hashcode 3459425
0, a, a, (0, push) with key hashcode 211641 and value hashcode 3459425
0, a, z, (0, push) with key hashcode 211666 and value hashcode 3459425
0, b, z, (1, push) with key hashcode 211697 and value hashcode 3459456
1, b, a, (1, pop) with key hashcode 212633 and value hashcode 117943
1, b, b, (1, push) with key hashcode 212634 and value hashcode 3459456

ababba

Transition from (0, a, z) with hashcode 211666
transition.equals(new TransitionState(0, "a", "z")) = true
HashMap containsKey() = false
Transition not found
false

如您所见,该键将哈希码与映射中的条目匹配,但有人告诉我这是不存在的。我尝试调试 HashMap 的 containsKey() 方法,该方法执行一个检查 NULL 的 get()。进入 get() 显示循环在返回 NULL 之前只运行一次。

那么,这是一个 HashMap 问题(可能不是)还是(更有可能)我做错了什么?提前感谢您的帮助。

【问题讨论】:

    标签: java hashmap


    【解决方案1】:

    你没有覆盖 equals 正确......你需要

     public boolean equals(Object other)
    

    目前你只是重载它。

    基本上 real 覆盖仍然可以完成与现有覆盖相同的工作,但首先要进行测试:

    if (!(other instanceof TransitionState))
    {
        return false;
    }
    TransitionState otherState = (TransitionState) other;
    // Now do the rest of the comparison
    

    请注意,在这种情况下您不需要检查 null,因为它会使 instanceof 测试失败。

    如今,Java 允许您添加注释以告诉编译器您确实在尝试覆盖父方法:

     @Overrides
     public boolean equals(Object other)
    

    现在编译器会告诉你是否在名称中输入了拼写错误或签名错误。

    【讨论】:

    • 应该始终使用@Overrides 的完美理由。
    • @matt b:我正要补充 :)
    • 天哪,您是对的。我非常专注于实现,最简单的事情让我着迷。像魅力一样工作。感谢您的及时回复。
    • 我无法表达找到这篇文章的喜悦之情。我正在为教育目的开发 DFA,并没有覆盖equals(),过去一个小时我坐在那里很沮丧,想知道为什么。现在可以了...可以了...我很高兴它可以正常工作了!!!
    【解决方案2】:

    乔恩是正确的。此外,您应该执行以下操作:

    使你的实例变量最终化:

    private final String mStackSymbol;
    private final String mTransitionSymbol;
    private final int mState;
    

    如果您不能这样做,请确保在将项目放入地图后没有更改这些变量的值。如果在您将它们放入地图后状态发生变化,您将无法再次将它们取出(至少不会按照它们的原始值)。

    【讨论】:

    • 我正在考虑这个问题,但我只是选择设计整个类,使其不能被修改(没有设置器,所有成员都是私有的,等等)。不过,我怀疑这会使类的设计对下线的人更容易理解。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-09
    • 1970-01-01
    • 1970-01-01
    • 2016-05-23
    • 2020-06-09
    • 1970-01-01
    • 2011-04-24
    相关资源
    最近更新 更多