我覆盖了一个类的hashCode和equals方法。我也为它编写了单元测试,它都是绿色的。当我用hashmap测试它时,我注意到一些奇怪的东西。 我创建了两个相同的对象:
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;
}
}
}
}
}
答案 0 :(得分: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;
}
答案 1 :(得分: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
答案 2 :(得分:0)
我无法重现您的错误。由于发布评论的时间太长,我会将其添加为答案,并在您展示HashCode
和Equals
实施后编辑我的帖子以解释您的错误。
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