Java 如何在HashMap中正确使用双坐标作为键?
我有一个类定义了一个节点(一个有三个双坐标的点) 我需要创建很多节点并给它们整数ID,但我必须避免重复 创建节点的方法如下所示:Java 如何在HashMap中正确使用双坐标作为键?,java,hashmap,Java,Hashmap,我有一个类定义了一个节点(一个有三个双坐标的点) 我需要创建很多节点并给它们整数ID,但我必须避免重复 创建节点的方法如下所示: private Node vertex = new Node(0, 0, 0); private final AtomicInteger nodeCounter = new AtomicInteger(); private final Map<Node, Integer> nodeList = new HashMap<>(); public
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;
}
私有节点顶点=新节点(0,0,0);
私有最终AtomicInteger节点计数器=新的AtomicInteger();
private final Map nodeList=new HashMap();
公共int addNode(最终双x、最终双y、最终双z){
顶点设置坐标(x,y,z);
int-nodeId;
if(nodeList.get(顶点)==null){
nodeId=nodeCounter.incrementAndGet();
nodeList.put(新节点(x,y,z),nodeId);
}否则{
nodeId=nodeList.get(顶点);
}
返回节点ID;
}
当然,这不起作用,因为HashMap
的get
函数总是返回null
所以我想我需要重写节点
类中的hashCode
方法
我已经看到了如何对单个double执行此操作,但我不知道如何创建一个考虑节点的三个坐标的哈希函数
我是否也必须重写equals
函数?或者hashCode函数足够了吗
所以我想我需要重写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
()首先:double
是64位类型,int
(hashCode()
的返回类型)是32位类型。因此,不可能进行无冲突映射,特别是当需要将三个double
s映射为一个int
时。第二:如果你重写hashCode()
,你就不需要重写equals(…)
,因为:@Turing85“如果你重写hashCode()
,你就不需要重写equals(…)
”是一个打字错误。你的话正好相反…@TimothyTruckle不。如果你仔细阅读合同,你会发现这句话是真的(除非你写了一个方法,它甚至忽略了语义,我认为这是强行破坏系统的)。注释以“如果两个对象根据equals(…)
”相等”开头,但OP没有覆盖equals(…)
“如果仔细阅读合同,您会发现这句话确实正确”不,我看不出来。特别是作为对OPS问题的注释,它完全是错误的,因为HashMap
使用equals
在hashcode
选择的bucket中查找密钥,并且在默认的equals
实现中找不到它。从技术上讲,您可以覆盖hashcode而不覆盖equals,但是这样做是毫无用处的,反之亦然:如果修改equals(…)
,则需要重写hashCode(…)
。在Java 8+中,Double.valueOf(x).hashCode()
应替换为Double.hashCode(x)
,以避免不必要的值装箱。为什么不返回Objects.hash(x,y,z)代码>?@MickMemonic你是对的-它比8之前的版本好。我认为Java-8方法稍微有效一些,因为没有拳击比赛。谢谢你的评论!
@Override
public int hashCode() {
return 31*31*Double.hashCode(x)
+ 31*Double.hashCode(y)
+ Double.hashCode(z);
}