简体   繁体   中英

Overwriting the hashCode() and equals() method in Java

As the heading suggests, my question has something to do with overriding the hashCode() and equals() method. However, this is also not completely true, I just did not know another way to summarize my question.

I have an object Label that contains multiple components, one of which is a List that contains multiple objects of type Node . An example of Label would be: [(n1, n2, n3), (n4, n5)] . I want to store all unique Label objects generated in a LinkedHashSet . However, this is not working as expected. Suppose that the LinkedHashSet currently contains the Label described above, and that we now generated a new Label called other which turned out to contain the same nodes as the already added label, thus also [(n1, n2, n3), (n4, n5)] . Since it has the same list of nodes, the other components in Label are also identical. I won't explain here why, just assume that it is, because that is the case. However, when checking if the LinkedHashSet already contains the Label it returns false , since the objects have different object ID's.

One approach would be to write a for-loop over the LinkedHashSet and compare the new label with all labels in the LinkedHashSet , but that would be very expensive in terms of running time, so I am looker for a cheaper option. Any suggestion is welcome!

Another approach would be to adapt the equals() method, but this was not working out, since I also have to adapt the hashCode() method and I do not know what to change this to to get this working.

You definitely don't want to "for-loop over the LinkedHashSet and compare..." Detecting duplicates is what the LinkedHashSet is supposed to do. In order to do that, it needs appropriate implementations of equals and hashCode .

You probably understand that you need to implement equals such that it returns true when a Label is "equal to" another Label , however you define that. If two labels are equal when they have the same nodes, then yeah, you pretty much have to look at all the nodes and check that they're the same.

That leaves hashCode . You must implement hashCode to be consistent with equals , that is, if two labels are equal, they must have the same hash code. That's because LinkedHashSet is going to use the hash code to determine the bucket in which a Label resides, and then use equals to compare the new Label with the ones that already exist in bucket. If two labels are equal but generate different hash codes, LinkedHashSet won't be able to detect them as duplicates.

The simplest thing to do would be to incorporate the hash codes of all the nodes into the hash code of the Label . Something like:

int hashCode() {
    int hc = 1;
    for (Node n : allMyNodes) {
        hc = hc * 31 + n.hashCode();
    }
    return hc;
}

If there are lots of nodes and it's unlikely that two labels will share the same node unless they're "equal," you could just use the hash code of the first node, instead of rummaging through them all.

Implementing equals(...) and hashCode(...) is the right approach here. Usually people use their IDE to generate those methods for them, here is what this would look like with Java 7+:

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Label label = (Label) o;
        return Objects.equal(nodes, label.nodes);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(nodes);
    }

If you have multiple fields this become:

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Label label = (Label) o;
        return Objects.equal(nodes, label.nodes) &&
                Objects.equal(other, label.other);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(nodes, other);
    }

However this will only work if the implementations for Node also implement equals(...) and hashCode(...) .

Use @EqualsAndHashCode from lombok at your Node (or Label ) class.

Then you can add nodes to your LinkedHashSet .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM