我有一个定义节点的类(一个有三个双坐标的点)。
public class Node {
private final double x, y, z;
public Node() {
}
public Node(final double x, final double y, final double z) {
this.x = x;
this.y = y;
this.z = z;
}
public void setCoordinates(final double x, final double y, final double z) {
this.x = x;
this.y = y;
this.z = z;
}
}
我需要创建大量节点并为它们提供整数ID,但我必须避免重复。
创建节点的方法如下所示:
private Node vertex = new Node(0, 0, 0);
private final AtomicInteger nodeCounter = new AtomicInteger();
private final Map<Node, Integer> nodeList = new HashMap<>();
public int addNode(final double x, final double y, final double z) {
vertex.setCoordinates(x, y, z);
int nodeId;
if(nodeList.get(vertex) == null) {
nodeId = nodeCounter.incrementAndGet();
nodeList.put(new Node(x, y, z), nodeId);
} else {
nodeId = nodeList.get(vertex);
}
return nodeId;
}
当然,这不起作用,因为get
的{{1}}函数始终返回HashMap
。
所以我想我需要覆盖null
类中的hashCode
方法。
我已经看过here如何为单个双精度操作,但我不知道如何创建一个考虑节点三个坐标的哈希函数。
我是否还必须覆盖Node
功能?或者hashCode函数是否足够?
答案 0 :(得分:7)
所以我想我需要覆盖Node类中的
hashCode
方法。
这只是交易的一部分。您还需要覆盖equals
,以使您的类作为哈希映射的键工作:
@Override
public int hashCode() {
return 31*31*Double.valueOf(x).hashCode()
+ 31*Double.valueOf(y).hashCode()
+ Double.valueOf(z).hashCode();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Node)) {
return false;
}
Node n = (Node)other;
return x == n.x && y == n.y && z == n.z;
}
在Java 8+中,Double.valueOf(x).hashCode()
应替换为Double.hashCode(x)
以避免不必要的装箱:
@Override
public int hashCode() {
return 31*31*Double.hashCode(x)
+ 31*Double.hashCode(y)
+ Double.hashCode(z);
}
我是否还必须覆盖
equals
功能?或者hashCode
功能是否足够?
是的,您必须始终覆盖equals
以及hashCode
(why?)