【问题标题】:Java TreeSet not adding objectJava TreeSet 不添加对象
【发布时间】:2016-10-24 19:34:53
【问题描述】:

我正在尝试将对象添加到树集中,但并非所有对象都被添加。

class Fruits
{
     String name ;
     int weight;
     int price;

    Fruits(String n, int w, int p)
    { 
        this.name=n;
        this.weight=w;
        this.price =p;
    }

    @Override
    public int hashCode() {
        System.out.println("hashcode called");
        int prime =31;
        int result =1;
        result = prime*result +(this.name.hashCode()+this.price+this.weight);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        System.out.println("Equals called");
        if(null!=obj)
        {
            Fruits f= (Fruits) obj;
            if(this.name.equals(f.name) && this.price==f.price && this.weight == f.price)
            {
                return true;
            }
        }
        return false;
    }
}

class FruitsComparator implements Comparator<Fruits>
{
    //Order by Name, then quanity and then Price
    @Override
    public int compare(Fruits f1, Fruits f2)
    {
        if(f1.name.equals(f2.name) && f1.weight == f2.weight && f1.price == f2.price)
        {
            System.out.println(1);
            return 0;
        }
        else if(f1.name.equals(f2.name) && f1.weight==f2.weight && f1.price < f2.price)
        {
            System.out.println(2);
            return -1;
        }
        else if (f1.name.equals(f2.name) && f1.weight==f2.weight && f1.price > f2.price)
        {
            System.out.println(3);
            return 1;
        }
        else if (f1.name.equals(f2.name) && f1.weight<f2.weight && f1.price == f2.price)
        {
            System.out.println(4);
            return -1;
        }
        else if (f1.name.equals(f2.name) && f1.weight>f2.weight && f1.price == f2.price)
        {
            System.out.println(5);
            return 1;
        }
        else if (f1.name.compareTo(f2.name) <1 && f1.weight==f2.weight && f1.price == f2.price)
        {
            System.out.println(6);
            return -1;
        }
        else if (f1.name.compareTo(f2.name) >1 && f1.weight==f2.weight && f1.price == f2.price)
        {
            System.out.println(7);
            return 1;
        }
            return 0;
    }       
}

来自另一个类的 public static void main。

Fruits f1= new Fruits("Apple",1,3);
Fruits f2= new Fruits("Apple",10,1);
Fruits f3= new Fruits("Apple",15,2);
Set<Fruits> sf = new TreeSet<Fruits>(new FruitsComparator());
sf.add(f1);
sf.add(f2);
sf.add(f3);
System.out.println("--Fruits Example--");
for( Fruits f: sf)
{
    System.out.println(f.name+"-"+f.weight+"-"+f.price);
}

我得到的输出是:

--Fruits Example--
Apple-1-3

但是当我有如下的水果对象时,我得到了所有的对象 只是保持一切不变,但第三个元素。 水果 f1= new Fruits("苹果",1,3); 水果 f2= new Fruits("苹果",1,1); 水果 f3= new Fruits("Apple",1,2);

得到的输出是

--Fruits Example--
Apple-1-1
Apple-1-2
Apple-1-3

所以当我在重量和价格上保留不同的元素时,不知何故我的物品被视为相同。我无法弄清楚为什么这些对象被视为相同。请帮忙。

【问题讨论】:

  • 投票结束时复制粘贴错误(f.price 应为 f.weight)。
  • 您的比较器实现如此混乱以至于无法阅读,更不用说修复了。此外,.compareTo 结果应与 0 进行比较,而不是 1。

标签: java collections treeset


【解决方案1】:

主要问题是,您总是检查两个字段是否相等,而只有一个字段不同。 在最后的 else 中,如果至少 2 个字段不同,则返回 0,这意味着它们应该被视为相等,这就是您遇到此问题的原因。

由于您想要的顺序是先按名称排序,然后按数量排序,然后按价格排序,因此从第 4 个条件开始删除&amp;&amp; f1.price == f2.price,并删除最后两个条件的&amp;&amp; f1.weight==f2.weight


如果你使用 Java 8 风格,你可以完全避免这个问题。

Set<Fruits> sf = new TreeSet<Fruits>(Comparator.comparing(Fruits::getName)
    .thenComparing(Fruits::getWeight)
    .thenComparing(Fruits::getPrice)
    );

我在codiva - online java compiler ide 中添加了工作代码。我还在 FruitsComparator.java 文件中包含了一个更简洁的实现。

【讨论】:

    【解决方案2】:

    TreeSet,当与Comparator一起使用时,元素的相等性由Comparatorcompare方法决定,否则将使用其元素的compareTo方法,因为它们需要实现Comparable 接口。 hashcodeequals 方法只会被Set 接口本身使用(例如方法contains 使用equals 方法来检查元素是否存在)。并且hashcode 不是TreeSet 使用的东西,而HashSet 使用它完全是实现Set 接口的另一种方式。因此,在您的代码中,由于您已覆盖 Comparatorcompare 方法将这些元素视为相等,因此它们不能被多次插入。 Java 教程指出的一个准则是,compare 方法应符合equals 方法,即,当且仅当equals 方法这样做时,compare 方法中的元素应被视为相等。

    在您的equals 方法中,您确实使用this.weight == f.price 比较了两种水果,我认为这不是您打算做的。这使您的equals 方法与compare 方法不一致。

    供你参考,见Java Object Ordering教程,还有我前两天问的a question

    【讨论】:

      【解决方案3】:

      与树相关的集合不使用equals()hashCode()。这些对Map起作用。

      compare 中的条件导致0,因此没有插入水果。

      第一个苹果进入,因为树是空的。第 2 和第 3 个 Apple 在所有 if 条件中产生 false,从而返回最终的 0。在最后的return 前加上System.out.println() 以确认。

      如果您想先按名称排序水果,然后按重量排序,最后按价格排序,这里有一个更紧凑的方法:

      @Override
      public int compare(Fruits f1, Fruits f2) {
          if (f1.name.equals(f2.name)) {
              if (f1.weight < f2.weight) {
                  return -1;
              } else if (f1.weight > f2.weight) {
                  return 1;
              } else {
                  if (f1.price < f2.price) {
                      return -1;
                  } else if (f1.price > f2.price) {
                      return 1;
                  } else {
                      return 0;
                  }
              }
          } else {
              return f1.name.compareTo(f2.name);
          }
      }
      

      【讨论】:

      • 谢谢。我相信这就是问题所在。但我不明白为什么在我的比较方法中满足条件。如果你有时间请看一下。谢谢。
      • 您的条件都不符合。在第 7 个之后放置 System.out.println(8),在完整的 if 块之后查看此内容。在每个if 条件下,您至少有一个nameweightprice 相等/==,而三个苹果中没有一个具有相同的weightprice
      【解决方案4】:

      您在 Fruits 类中的 equals 方法中有错误:

      if(this.name.equals(f.name) && this.price==f.price && this.weight == f.price)
      

      应该是:

      if(this.name.equals(f.name) && this.price==f.price && this.weight == f.weight)
      

      (注意最后一部分)。

      【讨论】:

      • 我改变了错字,但行为仍然没有改变。我相信我需要在比较器类中重新查看我的比较。谢谢。
      • TreeSet 和 TreeMap 不使用 equals 和 hashCode 方法。它们将用于 HashSet 和 HashMap。对于这个问题,它们是无关紧要的。查看我的答案以获得正确的解决方法。修复在比较器中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-13
      • 2016-06-28
      • 2014-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多