Java Hashmap两个相同的对象分开存储

问题描述 投票:2回答:3

我重写了类的hashCode和equals方法。我还为此编写了单元测试,而且全都是绿色的。当我用一个哈希表测试它时,我注意到了一些奇怪的东西。我创建了2个相同的对象:

obj1 = new PacmanVeld(field2);
obj2 = new PacmanVeld(field2);

我用这段代码对其进行了测试:

Assert.assertTrue(obj1.hashCode() == obj2.hashCode()); //works
Assert.assertTrue(obj1.equals(obj2)); //works

HashMap<PacmanVeld, Integer> testMap = new HashMap<>();
testMap.put(obj1, 5);

Assert.assertTrue(testMap.put(obj2, 7) == 5); //fails throws nullpointerexception
Assert.assertTrue(testMap.get(obj1) == 7); //fails 

我不明白为什么这不起作用,因为我了解在HashMap的算法中,obj1和obj2是相同的对象。

PacmanVeld类:

public class PacmanVeld
{
    private Node[][] nodes;

    public PacmanVeld(char[][] veld)
    {
        this.nodes = new Node[veld.length][veld[0].length];

        for (int i = 0; i < veld.length; i++)
        {
            for (int j = 0; j < veld[i].length; j++)
            {
                switch (veld[i][j])
                {
                    case '%':
                        nodes[i][j] = new Node(i, j, NodeType.WALL);
                        break;
                    case ' ':
                        nodes[i][j] = new Node(i, j, NodeType.EMPTY);
                        break;
                    case '.':
                        nodes[i][j] = new Node(i, j, NodeType.CRUMB);
                        break;
                    case 'P':
                        nodes[i][j] = new Node(i, j, NodeType.PACMAN);
                        break;
                }
            }
        }
        initFinish();
        initPacman();
    }

    //getters, setters & methods

    public boolean equals(PacmanVeld p)
    {
        if (p.nodes.length != nodes.length) { return false; }
        for (int i = 0; i < nodes.length; i++)
        {
            if (!Arrays.deepEquals(nodes[i], p.nodes[i])) { return false; }
        }
        return true;
    }

    @Override
    public int hashCode()
    {
        List<Node> nodeList = getNodeList();
        return Arrays.deepHashCode(nodeList.toArray());
    }

    private void initPacman()
    {
        for (Node[] rij : this.nodes)
        {
            for (Node n : rij)
            {
                if (n.isPacman())
                {
                    pacman = n;
                }
            }
        }
    }
}
java junit hashmap hashcode
3个回答
3
投票

问题是您没有重写从对象类继承的equals()方法。

@Override
public boolean equals(Object o)
    {
        PacmanVeld p = (PacmanVeld)o;
        if (p.nodes.length != nodes.length) { return false; }
        for (int i = 0; i < nodes.length; i++)
        {
            if (!Arrays.deepEquals(nodes[i], p.nodes[i])) { return false; }
        }
        return true;
    }

0
投票

我无法重现您的错误。由于发表评论的时间太长,一旦您显示了HashCodeEquals的实现,我将其添加为答案并编辑我的文章以解释您的错误。

public class Test {
    public static void main(String[] args) {
        Map<MyPersonalClass, Integer> map = new HashMap<>();
        MyPersonalClass obj1 = new MyPersonalClass();
        obj1.someInt = 5;
        obj1.someString = "test";

        MyPersonalClass obj2 = new MyPersonalClass();
        obj2.someInt = 5;
        obj2.someString = "test";

        System.out.println(obj1.equals(obj2));
        System.out.println(obj1.hashCode() == obj2.hashCode());

        map.put(obj1, 5);
        System.out.println(Arrays.toString(map.values().toArray()));

        System.out.println(map.put(obj2, 10) == 5);
        System.out.println(Arrays.toString(map.values().toArray()));
        System.out.println(map.get(obj1));
    }
}

class MyPersonalClass {
    public String someString;
    public int someInt;

    @Override
    public boolean equals(Object arg0) {
        if(arg0 == this) { return true; }
        if(!(arg0 instanceof MyPersonalClass)) { return false; }

        MyPersonalClass obj = (MyPersonalClass) arg0;

        return obj.someString.equals(this.someString) && obj.someInt == this.someInt;
    }

    @Override
    public int hashCode() {
        return this.someString.hashCode() * 37 + this.someInt;
    }
}

输出:

是真正[5]真正[10]10


0
投票

HashMap返回null作为新值。您的Assert.assertTrue(testMap.put(obj2, 7) == 5);测试用例将引发NPE异常,因为obj2中不存在HashMap。您可以使用已经放在HashMap上的obj1进行测试

  Assert.assertTrue(testMap.put(obj2, 7) == 5); 
                  //throws NPE because obj2 is not inserted

尝试使用obj1

  Assert.assertTrue(testMap.put(obj1, 7) == 5); 
          //will retrun true because, 5 is last inserted value with obj1
  Assert.assertTrue(testMap.put(obj1, 7) == 8); 
         // will retrun false because
© www.soinside.com 2019 - 2024. All rights reserved.