简体   繁体   English

Java Set 移除“复杂对象”

[英]Java Set removes “complex object”

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.我总是对 Java Collections (set, map) 删除“复杂对象”感到困惑,我的意思是一些自定义类而不仅仅是原始类型。

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.显然,一般的 Set 不能删除new Node(1, 2) ,它被视为不同的对象。 But interestingly the TreeSet can remove, which I think because the hashing code is based on the lambda comparator I defined here?但有趣的是 TreeSet 可以删除,我认为这是因为散列代码基于我在这里定义的 lambda 比较器?

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.如果我更改为 remove new Node(1, 6) ,有趣的是它是相同的打印输出,显然 TreeSet 中的 remove 仅基于名称值。

I think I still lack of deep understanding of how Set build up hashing and how comparator would affect this.我想我仍然缺乏对 Set 如何建立散列以及比较器将如何影响它的深入了解。

For HashMap and HashSet , you need to overwrite hashCode() and equals(Object) , where if two objects are equal, they should have equal hash codes.对于HashMapHashSet ,您需要覆盖hashCode()equals(Object) ,如果两个对象相等,则它们应该具有相同的哈希码。 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 ).对于TreeMapTreeSet ,相等的概念基于比较(类是否实现Comparable ,或者您提供自定义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 .在您提供的代码中,您有一个自定义Comparator只考虑name ,因此它会将任何两个具有相同name Node视为相等,而不管它们的price

javadoc comes to rescue javadoc 来拯救

https://docs.oracle.com/javase/7/docs/api/java/util/Set.html#remove(java.lang.Object) 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.更正式地,删除元素 e 使得 (o==null ? e==null : o.equals(e)),如果这个集合包含这样一个元素。 Returns true if this set contained the element (or equivalently, if this set changed as a result of the call).如果此集合包含元素(或等效地,如果此集合因调用而更改),则返回 true。 (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.因此,只需更改您的 Node 类并使用您自己的方法覆盖 equals(Object o) 方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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