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

时间:2018-01-07 23:37:11

标签: java hashmap

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

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函数是否足够?

1 个答案:

答案 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以及hashCodewhy?