[英]Java Set removes “complex object”
我总是对 Java Collections (set, map) 删除“复杂对象”感到困惑,我的意思是一些自定义类而不仅仅是原始类型。
我正在尝试:
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;
}
}
在上面的示例中,打印输出将是:
Set:
[Node@5ba23b66, Node@2ff4f00f]
[Node@5ba23b66, Node@2ff4f00f]
TreeSet:
[Node@48140564, Node@58ceff1]
[Node@58ceff1]
显然,一般的 Set 不能删除new Node(1, 2)
,它被视为不同的对象。 但有趣的是 TreeSet 可以删除,我认为这是因为散列代码基于我在这里定义的 lambda 比较器?
如果我更改为 remove new Node(1, 6)
,有趣的是它是相同的打印输出,显然 TreeSet 中的 remove 仅基于名称值。
我想我仍然缺乏对 Set 如何建立散列以及比较器将如何影响它的深入了解。
对于HashMap
和HashSet
,您需要覆盖hashCode()
和equals(Object)
,如果两个对象相等,则它们应该具有相同的哈希码。 例如,在您的情况下,您可以这样实现:
@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);
}
对于TreeMap
和TreeSet
,相等的概念基于比较(类是否实现Comparable
,或者您提供自定义Comparator
)。 在您提供的代码中,您有一个自定义Comparator
只考虑name
,因此它会将任何两个具有相同name
Node
视为相等,而不管它们的price
。
javadoc 来拯救
https://docs.oracle.com/javase/7/docs/api/java/util/Set.html#remove(java.lang.Object)
如果存在,则从此集合中删除指定的元素(可选操作)。 更正式地,删除元素 e 使得 (o==null ? e==null : o.equals(e)),如果这个集合包含这样一个元素。 如果此集合包含元素(或等效地,如果此集合因调用而更改),则返回 true。 (一旦调用返回,该集合将不包含该元素。)
因此,只需更改您的 Node 类并使用您自己的方法覆盖 equals(Object o) 方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.