使用Set - 自动删除重复项?

时间:2013-06-20 19:29:50

标签: java collections set duplicates

我有一个如下课程(Bean):

class KeysHolder {
   Long kitId;
   String packId;
   String boxId;

   // getters and setters
    .......
   // @Override equals and hashCode
}

我有一个包含上述对象的集合

 Set<KeysHolder> keys;

现在,如果我继续将对象添加到集合中,它是否会根据每个元素的值自动删除重复项? (我知道它在内部使用了重写的equals和hashCode方法。)

最终集不应包含基于每个字段相等的任何重复项。

  obja.kitId = objb.kitId
  objb.packid = objb.packId
  obja.boxId = objb.boxId

谢谢!

5 个答案:

答案 0 :(得分:6)

  

现在,如果我继续将对象添加到集合中,它是否会根据每个元素的值自动删除重复项。

如果Set实现发现重复的元素,则根本不会插入。

来自HashSet#add(E e)的Javadoc:

  

如果指定的元素尚不存在,则将其添加到此集合中。更正式地说,如果此集合不包含元素e2,使得(e == null?e2 == null:e.equals(e2)),则将指定的元素e添加到此集合中。如果此set已包含该元素,则调用将保持set不变并返回false。

答案 1 :(得分:2)

是的,任何Set实施都不允许重复。

但是,它有一个警告。对于Set和其他基于哈希的集合,您需要确保您尝试插入的对象正确覆盖其equals()hashCode()方法。

正确的说,我的意思是equals()应该为两个有意义的等效对象返回true,并且hashCode()应该尝试为您的对象范围尽可能不同的值返回输入集。

虽然不恰当的equals()实施很可能会破坏您的计划;效率低下的hashCode()实施会降低Set的效果,例如add()contains()等操作会像执行一样慢。

答案 2 :(得分:2)

简短回答是,任何一组都会自行执行重复数据删除。但只有在尊重合同的情况下才能保证;并且每个Set实现的合同有点不同:

对于HashSet,正如您所注意到的,您必须实施hashCode()equals()。但这还不够:如果您在HashSet中保留可变实例并修改影响hashCode() / equals()结果的属性,您仍将结束在奇怪的情况下。

另一方面,使用TreeSet,您需要确保Comparable.compareTo()Comparator.compare()方法与equals()一致。

请阅读Set的文档以及适合您需求的实际实现文档,并尝试遵守合同。

答案 3 :(得分:1)

HashSet在内部使用HashMap,这个地图用key维护,因为你要在set中添加的值和value是Object类的一个实例( final private static final Object PRESENT = new Object(); )。现在,当您向此集添加相同的对象时,它与map在同一个键上使用相同的map.put进行相同的操作,只需更新该值。

但是,要更新的值仍然与 PRESENT 相同。因此,在某种程度上,您可以说该集合不会添加相同的值。虽然实际上,内部用于实现此集的地图正在使用 * 相同的 *和相同的值(PRESENT)进行更新。

答案 4 :(得分:0)

我已经写了一个示例来说明如何在班级的一个字段(此处为name)中删除重复的员工条目:

public class Employee {
    private String id;
    private String name;
    private String age;
    public Employee(String i, String n, String a) {
        id = i; name = n; age = a;
    }
    @Override
    public boolean equals(Object obj) {
        if (obj == this) { 
            return true; 
        } 

        if (!(obj instanceof Employee)) { 
            return false; 
        }

        Employee e = (Employee) obj;

        return name.equals(e.name); 
    }
    @Override
    public int hashCode() {
        return name.hashCode();
    }
    @Override
    public String toString() {
        return id + " " + name + " " + age;
    }
    public static void main(String[] args) {
        Employee e1 = new Employee("1", "abc", "10");
        Employee e2 = new Employee("2", "def", "20");
        Employee e3 = new Employee("3", "abc", "30");
        HashSet<Employee> empSet = new HashSet<>();
        empSet.add(e1);
        empSet.add(e2);
        empSet.add(e3);
        System.out.println(empSet.toString());
    }
}

我要做的就是在Employee类中重写方法hashCodeequals。它打印:

[1 abc 10, 2 def 20]