Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何在HashMap中正确使用双坐标作为键?_Java_Hashmap - Fatal编程技术网

Java 如何在HashMap中正确使用双坐标作为键?

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

我有一个类定义了一个节点(一个有三个双坐标的点)

我需要创建很多节点并给它们整数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;
}
私有节点顶点=新节点(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);
}