I'm always confused about the Java Collections (set, map) remove "complex object", which I mean some self-defined class rather than just primitive type.
I'm experimenting like:
public class Main {
public static void main(String[] args) {
// set
Set<Node> set = new HashSet<>();
set.add(new Node(1,2));
set.add(new Node(3,4));
System.out.println(set);
set.remove(new Node(1,2));
System.out.println(set + "\n");
// tree set
TreeSet<Node> tset = new TreeSet<>((a, b) -> a.name - b.name);
tset.add(new Node(1,2));
tset.add(new Node(3,4));
System.out.println(tset);
tset.remove(new Node(1,2));
System.out.println(tset);
}
}
class Node {
int name;
int price;
Node(int name, int price) {
this.name = name;
this.price = price;
}
}
In the example above, the printout would be:
Set:
[Node@5ba23b66, Node@2ff4f00f]
[Node@5ba23b66, Node@2ff4f00f]
TreeSet:
[Node@48140564, Node@58ceff1]
[Node@58ceff1]
Obviously, the general Set can't remove new Node(1, 2)
, which is treated as a different object. But interestingly the TreeSet can remove, which I think because the hashing code is based on the lambda comparator I defined here?
And if I change to remove new Node(1, 6)
, interestingly it's the same printout, where obviously the remove in TreeSet is based on only the name value.
I think I still lack of deep understanding of how Set build up hashing and how comparator would affect this.
For HashMap
and HashSet
, you need to overwrite hashCode()
and equals(Object)
, where if two objects are equal, they should have equal hash codes. Eg, in your case, you could implement it like this:
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
Node node = (Node) o;
return name == node.name && price == node.price;
}
@Override
public int hashCode() {
return Objects.hash(name, price);
}
For TreeMap
and TreeSet
, the notion of equality is based on a comparison (whether the class implements Comparable
, or you supply a custom Comparator
). In the code you provided, you have a custom Comparator
that only takes the name
in to consideration, so it would consider any two Node
s with the same name
as being equal, regardless of their price
.
javadoc comes to rescue
https://docs.oracle.com/javase/7/docs/api/java/util/Set.html#remove(java.lang.Object)
Removes the specified element from this set if it is present (optional operation). More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if this set contains such an element. Returns true if this set contained the element (or equivalently, if this set changed as a result of the call). (This set will not contain the element once the call returns.)
So just change your Node class and override equals(Object o) method with your own.
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.