TreeSet存储重复的自定义对象

时间:2016-06-14 10:59:25

标签: java set comparable

你好,我可能会监督一些事情,但现在就去了 我有一个TreeSet<CustomObject>,我不想在Set中有重复项。我的CustomObject课程看起来像这样。

class CustomObject implements Comparable<CustomObject> {

    String product;
    String ean;

    public CustomObject(String ean){
      this.ean = ean; 
      // product is getting set via setter and can be null
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        CustomObject that = (CustomObject) o;

        return ean.equals(that.ean);

    }

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

    @Override
    public int compareTo(CustomObject another) {
        if(equals(another)) return 0;
        if(product != null && another.product == null) return -1;
        if(product == null) return 1;

        return product.compareToIgnoreCase(another.product);
    }
}

现在我为新对象添加了一个函数。

private final TreeSet<CustomObject> productCatalog;

public void addObject(SomeData tag) {
    CustomObject p = new CustomObject(tag.getEan());

    if (productCatalog.contains(p)) { // <-- This checks only one entry of the Set.
        for (CustomObject temp : productCatalog) {
            if (temp.equals(p)) {
                p = temp; // I do stuff with that later which is irrelevent here
            }
        }
    } else {
       productCatalog.add(p);
    }   
} 

方法productCatalog.contains(p)compareTo接口调用Comparable方法并进行比较。这里的问题是,它只是检查我认为最后一个对象?在集合中。所以会发生的是只存在一个唯一的CustomObject条目。

这是我使用调试器跟随它的情况:

  1. productCatalog.contains(p)
  2. 致电compareTo
  3. 致电equals以检查ean.equals(that.ean)
  4. 一次返回true,但每次都返回false。因为它只检查最后一个对象
  5. 如何让它不仅检查步骤4中的一个对象,还检查Set中的所有当前对象。我错过了什么?

    THX!

    编辑:这些是一些示例数据。为简单起见SomeData tag基本上是一个字符串。

    First run:
    
    addObject("Ean1") // success added
    addObject("Ean2") // success added
    addObject("Ean3") // success added
    addObject("Ean4") // success added
    

    所有内容都会添加到TreeSet中。

    Second run:
    addObject("Ean1") // failed already in the map
    addObject("Ean2") // failed already in the map
    addObject("Ean3") // failed already in the map
    addObject("Ean5") // success added
    addObject("Ean4") // success added
    addObject("Ean4") // success added
    

    出于测试目的,我根据字符串ean手动设置产品名称。

    public CustomObject(String ean){
          this.ean = ean; 
           switch(ean){
                case "Ean1": product = "TestProduct"; break;
                case "Ean2": product = "ProductTest";break;
                case "Ean3": product = "Product";break;
        }
    

    TreeSet充当缓存。

    Edit2:这就是我解决它的方法。

                for (CustomObject temp : productCatalog) {
                    if (temp.equals(p)) {
                        p = temp; // I do stuff with that later which is irrelevent here
                    }
                }
    

    我使用contains方法删除了if语句,因为它始终返回'1 or - 1 in my special case. Now I simply iterate over the Set to correctly use the equals`方法,因为TreeSet使用compareTo()来检查每个元素集。

    Java Docs陈述以下内容

      

    注意由一组维护的排序(无论是否显式   比较器提供)必须与equals一致,如果是的话   正确实现Set接口。 (参见可比较者或比较者   对于与equals一致的精确定义。)就是这样   因为Set接口是根据equals操作定义的,   但 TreeSet实例使用它执行所有元素比较   compareTo(或compare)方法,因此两个被认为相等的元素   从该集合的角度来看,通过这种方法是相等的。该   集合的行为即使其排序不一致也是明确定义的   与...平等它只是没有遵守集合的一般合同   接口

1 个答案:

答案 0 :(得分:1)

主要问题:

如果product和other.product都为null,则

compareTo会返回1。这是错误的,因为它们实际上是平等的。您可能忘记为更高的ean值设置产品名称,例如&#34; Ean4&#34;和&#34; Ean5&#34;。

旧答案:

equalscompareTo的实施不适合。

equals适用于产品上的ean和compareTo。这只有在您隐含地假设等于ean意味着同等产品时才有效。如果在您的测试用例中不是这样,那么结果将是错误的。

在任何一种情况下,都不是很好的实施,因为这可能导致&lt; b,b&lt; c但是等于&#34;等于&#34;角